Skip to content

Restore plugin-audit's README "See Also" link to runtime-services/audit-service, dropped in PR #9531 because the page was wrong #9589

Description

@os-steve

Blocked-by: #9534

Found while implementing #9534. Reported rather than fixed: packages/plugins/plugin-audit/README.md is #9517's file and outside that card's pinned surface.

Background

#9517 rewrote plugin-audit's published README. Its old "See Also" section linked content/docs/kernel/runtime-services/audit-service.mdx as the reference for the audit service. While checking whether that link was safe to keep, the author measured the page's claims and found them wrong — it documented record() / 'set' | 'reset' (the settings sink) rather than the slot's real recordAuthEvent() / 'login' | 'logout'. PR #9531 therefore dropped the link rather than propagate a claim measured to be wrong, and filed the page's defect as #9534.

What to do once #9534 lands

PR #9587 rewrites that page around the real slot: recordAuthEvent(event), action: 'login' | 'logout', canonical source packages/plugins/plugin-audit/src/auth-event-audit.ts. The README's own "The audit service slot" section (added by #9531) and the rewritten page now describe the same shape in the same terms, so the reason the link was dropped no longer holds.

⇒ Consider restoring the "See Also" pointer to /docs/kernel/runtime-services/audit-service.

Why it is not automatic

Two things deserve a decision rather than a reflex:

  1. check:published-readme-symbols (added in ci: a published README's symbol claims are checked against the package's built exports #9546) now checks a published README's symbol claims against the package's built exports. Whether it has anything to say about an outbound docs-site link should be confirmed before adding one.
  2. The README section docs(plugin-audit): the published README stops documenting an API, a row shape and an action vocabulary that do not exist (#9517) #9531 wrote is self-contained — it already states the full surface. The link is worth restoring only if the page adds something the README deliberately does not carry (the error posture, the organizationId visibility note, the settings-sink disambiguation). That is a judgment call for whoever owns the published README's scope, not a mechanical revert.

⚠️ Small scope. Blocked until #9534 is merged — restoring the link before that would re-point readers at the page in its wrong state.

Refs: #9517 · PR #9531 · #9534 · PR #9587

Activity

  1. os-steve commented on Aug 18, 2026

    @os-steve
    CollaboratorAuthor

    Claiming this card.

    • session: session_01XqDQYVU5smx29ts9pAErja
    • branch: claude/issue-9589-plugin-audit-see-also
    • worktree: ../objectstack-9589 off current origin/main

    Scope: decide (not reflexively perform) whether plugin-audit's published README should regain a "See Also" pointer to the runtime-services audit-service page, now that PR #9587 has rewritten that page around the real slot. Also measuring the four PM hypotheses on this card: what check:published-readme-symbols actually covers, whether anything verifies a published README's docs-site link resolves, the established spelling convention for docs links in published READMEs, and whether any other README carries the same deliberate omission.


    Generated by Claude Code

  2. os-steve commented on Aug 18, 2026

    @os-steve
    CollaboratorAuthor
    {
      "issue": 9589,
      "status": "done",
      "branch": "claude/issue-9589-plugin-audit-see-also",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/9636",
      "premise_still_valid": true,
      "summary": "VERDICT: RESTORE — but not the line PR #9531 removed. Ruling 1 holds: the page at 14935ab71 documents recordAuthEvent(event) (line 24), action: 'login' | 'logout' (line 25) and canonical source packages/plugins/plugin-audit/src/auth-event-audit.ts (line 9); the settings sink appears only under an explicit 'Not this: the settings audit sink' heading stating it is never registered as or resolved from the slot and that getService('audit').record({...}) throws TypeError — disambiguation, the opposite of the defect #9531 measured. Ruling 2 holds on ALL THREE named candidates, none of which the README carries: (a) error posture — recordAuthEvent never throws, error once per process then debug, row lost, nothing retries, silent no-op with no engine or no userId; the README's only failure postures (lines 217-224) belong to the record-view batcher, a different code path, and its slot section (291-304) states none; (b) organizationId visibility — page line 45 ties it to the row's tenant columns and non-admin invisibility, while the README's tenant note (231-234) is about read rows from the record-view writer and the slot section never enumerates the event's fields at all; (c) settings-sink disambiguation with the TypeError consequence — the README names config_change's writer but never distinguishes SettingsAuditSink.record() from the slot. The page additionally carries the whole event shape (userId must be a real sys_user id; sessionId lands on record_id with object_name fixed to sys_session; context serialized into metadata), which the README abstracts behind AuthSessionAuditEvent — so the page is the only place a reader learns what to put in the event. Not a redundant link. The removed line was wrong twice independently of the page defect: label 'Audit Logging Best Practices' (the page is a slot reference, never a guide) and URL /content/docs/.../audit-service.mdx, which resolves on none of the three surfaces. Restored as the absolute https://docs.objectstack.ai/docs/kernel/runtime-services/audit-service with an annotation stating what the page adds, so the next author can check the justification instead of reconstructing it. ONE IN-PLACE FIX DECLARED (bounded-exemption, same file, declared in the PR body): README line 343's /docs/permissions/permission-sets#access-depth... — the only site-root-relative docs link in the whole packages/ tree, added by the same PR #9531 — converted to the same absolute form; its page and heading anchor both exist (content/docs/permissions/permission-sets.mdx:111), only the spelling was unfollowable off the docs site. Boundary scan: grep -rn '](/docs' --include=README.md packages/ was 1 hit before, 0 after. The 7 links in 5 OTHER packages are untouched and filed as #9632. Cosmetic note for PM: the platform appended a second identical signature footer to the PR body at creation; left as-is rather than risk double-encoding a 10KB body on edit.",
      "tests": "Local gate union run AFTER the final commit, at a15cc19df (git rev-parse --short HEAD from that run): check:nul-bytes OK ('scanned 6176 text file(s) -- 6176 tracked, 0 untracked-not-ignored; skipped 5 binary; no raw ASCII control bytes', exit 0); check:published-readme-exports --self-test OK ('extraction, scoping, resolution and both analysis directions pinned', exit 0); check-adr-0087-registration OK ('this PR adds no declared-breaking changeset (1 non-breaking changeset(s) seen)', exit 0); check-empty-changeset OK ('No empty-frontmatter changeset introduced by this diff (1 declaring changeset(s) added)', exit 0); check-changeset-no-major OK ('This diff introduces no major bump', exit 0); check:test-source-alias OK ('72 packages with tests scanned; 61 registered', exit 0); check:type-source-resolution OK ('76 packages with a tsconfig.json scanned; 51 registered', exit 0); check-affected-docs OK ('affected-docs self-test: 242 cases pass', exit 0). Gate set re-derived from the ACTUAL changed paths (node scripts/pm/dispatch-gates.mjs packages/plugins/plugin-audit/README.md .changeset/plugin-audit-readme-audit-service-link.md), which added the four changeset families the README-only derivation had not named; all four were then run and are in the union above. TWO gates reasoned rather than run, both build-dependent, each with its measurement: (1) check:published-readme-exports full run hard-errors without built dist/ for every workspace package any published README imports (i.e. a whole-workspace build) and runs in the CI job that has already built — its --self-test passes, and I measured that all four changed lines (343, 395-397) sit outside every fenced block in the file (fences at 24-26, 33-37, 43-49, 164-166, 296-300, 360-387), while the gate reads fenced code blocks only, so this diff is outside its reading surface entirely; (2) check:i18n is convention-triggered because plugin-audit owns scripts/i18n-extract.config.ts and needs @objectstack/cli built — that config's input set is three object modules (sys-audit-log/sys-activity/sys-comment .object.js) plus generated bundles, which a markdown prose edit cannot move. NO ABLATION was applicable: this diff changes no code, only markdown prose. No test pins this README's content (grep -rn README --include=*.test.ts over packages/ yields no plugin-audit hit; the one structural reference, packages/spec/src/kernel/plugin-structure.test.ts, uses the literal string 'README.md' as a schema fixture). Changeset shipped (@objectstack/plugin-audit: patch), matching the precedent of the two prior README-only PRs on this package (#9531, #9541), both of which shipped one because the README is in the published files array. skip-changeset label not applicable.",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #9632: seven docs links in five published READMEs (service-automation x3, service-job, service-cache, service-analytics, service-i18n) are spelled /content/docs/..., a path that resolves on NONE of the three surfaces — not npm, not GitHub, and not the docs site itself (apps/docs/lib/source.ts mounts loader({baseUrl:'/docs'}) over content/docs, and apps/docs/redirects.mjs has no /content source); every target file exists, so this is spelling, not rot. Same card carries the H2 durable half: no gate reads a published README's links at all, with a contained three-assertion proposal and sizing that reuses the resolvers check-docs-redirects and check-doc-anchors already have. Unassigned, unlabelled (concrete defect, left for PM triage). Searched first: no open card covers it (#9614/#9579/#9544/#9545 are the gate's SYMBOL population, #9588 is a docs-site page, #9626 is dispatch-gates)."
      ],
      "pm_hypotheses": {
        "H1": "CONFIRMED, plus a naming correction. The gate is check:published-readme-exports, not check:published-readme-symbols — no script or package.json entry by the latter name exists; PR #9546 added scripts/check-published-readme-exports.mjs (lint.yml:1723). It has NOTHING to say about an outbound docs-site link: its header states it is 'deliberately NOT a docs linter', it reads fenced code blocks only (typescript/ts/tsx/diff/untagged) and makes one claim per import line plus one per Name.member( call site against the built .d.ts. Its only '](' occurrences are its own header prose and self-test fixtures. Your expectation held. Bonus finding for future cards: scripts/published-readme-exports.baseline.json names @objectstack/plugin-audit as the gate's deliberate NEGATIVE CONTROL ('fixed by PR #9531 before this gate landed and is deliberately ABSENT... the PR that added this gate reports it clean') — so this file must stay clean, not merely unbaselined.",
        "H2": "GAP IS REAL — nothing verifies a published README's docs-site link resolves, neither the page nor the anchor. Measured across every candidate: the lychee lane (check-links.yml LYCHEE_ARGS) runs over exactly content/**/*.md, content/**/*.mdx, README.md, ARCHITECTURE.md — packages/**/README.md is not in scope; check:doc-anchors takes sources from content/** plus EXTRA_SOURCES = ['README.md','ARCHITECTURE.md'], the ROOT README only; check:adr-links is scoped to docs/adr/; check:docs-redirects to apps/docs/redirects.mjs; check:published-readme-exports per H1. A published README can link anywhere, in any spelling, and ship to npm green — and an npm tarball outlives any in-repo correction. Filed as #9632 with the proposal and sizing.",
        "H3": "THE CARD'S SHORTHAND WAS THE WRONG FORM, AND THE REPO IS INCONSISTENT — four coexisting spellings. (1) absolute https://docs.objectstack.ai/docs/... — create-objectstack/README.md:90 and the blank template at 39/70/108; the ONLY form that works on all three surfaces, verified against four sample targets that all exist; adopted here. (2) /content/docs/... — 7 links, 5 packages; dead everywhere; filed as #9632. (3) /docs/... — 1 link, plugin-audit:343, the only one in the whole packages/ tree, converted in this PR. (4) ../../../content/docs/... — 2 links (service-knowledge:8, knowledge-ragflow:5); these DO resolve on GitHub and npm but land the reader on raw MDX source rather than the rendered page, so a milder quality issue, listed in #9632 for completeness rather than as part of its claim. The card's /docs/kernel/runtime-services/audit-service was the second-rarest form in the tree and resolves off the docs site for nobody.",
        "H4": "NO — plugin-audit is the only one. Swept every package README for omission markers (deliberately / intentionally / on purpose / dropped / omitted / restore / 'once #' / Blocked-by) and read every '## See Also' section in the tree. All hits are unrelated: service-realtime's deliberately-unimplemented handleUpgrade, service-automation's deliberate non-duplication of the per-node flow reference, http-conformance's 'deliberately absent' escape hatches, driver-mongodb's deliberate absence of an override flag, and the spec liveness ledger's vocabulary. No other published README carries a comment, gap or card reference recording a link withheld pending a page fix. The nearest adjacent case — runtime-services/index.mdx pointing 'Audit bridge' at the settings sink — is already open as #9588 and is a docs-site page, not a README."
      }
    }

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions