Repository navigation
Restore plugin-audit's README "See Also" link to runtime-services/audit-service, dropped in PR #9531 because the page was wrong #9589
Copy link
Copy link
Closed
Labels
Description
Activity
- added and removed
on Aug 18, 2026 Claiming this card.
- session:
session_01XqDQYVU5smx29ts9pAErja - branch:
claude/issue-9589-plugin-audit-see-also - worktree:
../objectstack-9589off currentorigin/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-symbolsactually 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
- session:
- added a commit that references this issue
on Aug 18, 2026 { "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
- added a commit that references this issue
on Aug 23, 2026 - added a commit that references this issue
on Sep 28, 2026
Blocked-by: #9534
Found while implementing #9534. Reported rather than fixed:
packages/plugins/plugin-audit/README.mdis #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.mdxas 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 documentedrecord()/'set' | 'reset'(the settings sink) rather than the slot's realrecordAuthEvent()/'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 sourcepackages/plugins/plugin-audit/src/auth-event-audit.ts. The README's own "Theauditservice 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:
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.organizationIdvisibility note, the settings-sink disambiguation). That is a judgment call for whoever owns the published README's scope, not a mechanical revert.Refs: #9517 · PR #9531 · #9534 · PR #9587