exp/core-dossiers
needs attentionviewing older commita516a9d · incrementalPR #270reviewed 2026-07-17 04:38 UTC4H · 5M · 4L · 3I- Purpose
- Stand up a capability-dossier knowledge system for the FE + public-API surface (the projection that backend ontology/FCIS docs never covered), and populate it with 9 audited core-domain dossiers.
- Goal
- Replace the 'dossier as enforcement gate' model with 'dossier as assistive map + mechanical lint fence', add the FCIS-boundary ESLint rule as the real enforcement wall, and preserve the audit artifacts separately from living dossiers.
- Sub-goals
- SG-1: Demote capability-dossier.md from blocker/gate to assistive reference
- SG-2: Add FCIS-boundary ESLint rule (warn) to apps/platform/eslint.config.mjs targeting handlers/
- SG-3: Add audit/ subdirectory with canonical-api-form + per-entity audit snapshots
- SG-4: Refine V1 finding — coordinator pattern is NOT a bug; only profile signup (BAT-269) is real
- SG-5: Strip check-freshness machinery (Mode D) from dossier skill
- What
- Pivoted the dossier system from 'enforcement gate' to 'assistive map'. Added the first mechanical FCIS-boundary lint rule (warn). Added audit/ subfolder with canonical API form doc + 6 per-entity audit snapshots. Stripped YAML front-matter from 8 entity dossiers. Refined V1 bug finding to narrow from 4 suspected violations to 1 confirmed (profile only). Removed Mode D (freshness check).
- Why
- The freshness-gate model was fragile (pnpm dossier:check was never wired into CI; the 'same PR blocker' language was not enforceable). Moving enforcement to mechanical lint (ESLint FCIS-boundary rule) creates a real, code-level fence while keeping dossiers as high-signal, human-curated reference docs.
- Areas
- .claude/rules+13−46.claude/skills/dossier/references/audit+993−0.claude/skills/dossier/references/entities+16−91.claude/skills/dossier/references+25−16.claude/skills/dossier+15−29apps/platform+45−0
- Blast
- 22 files, +2552/-0 cumulative vs main; this commit +1107/-182. Zero runtime changes — all .claude/ docs + one eslint config. No migrations, no domain code, no API contracts touched.
Findings · 16
correctness5
_audit-index.md contradicts _findings.md V1 on membership — same commit, opposite verdicts
.claude/skills/dossier/references/audit/_audit-index.md:12
_audit-index.md (new in this commit) labels 'createMembershipShell has zero callers' as a hard blocker (V1 dead create shell). _findings.md (also updated in this commit) explicitly says this is NOT a bug: 'Coordinators legitimately compose decisions + write the outbox directly.' Same commit ships both — readers will see contradictory verdicts on the same code path. The audit/membership.md also repeats the pre-refinement verdict at line 39.
no-restricted-imports doesn't catch barrel re-export imports (actual violation pattern in use)
apps/platform/eslint.config.mjs:88
The patterns ['**/*.queries', '**/*.queries.*', '**/queries/*'] only catch direct filesystem imports ending in .queries. Real violations import from FCIS/domain barrels (e.g. '@batu/utility-domain/cfe-job') — these don't match the pattern. The no-restricted-syntax call-site selector compensates, but the import-level gate provides no additional coverage and may give false assurance.
ESLint comment references non-existent 'fix-strat' document — dangling pointer
apps/platform/eslint.config.mjs:67
Line 67: 'handled by the fix-strat' — no file named fix-strat exists in the repo. The reference is a dangling pointer. A reader cannot locate the referenced strategy.
ESLint AST selectors are correctly formed and match the intended violation patterns
apps/platform/eslint.config.mjs:76
Both selectors verified via AST: selector 1 (callee.object.name=/[Qq]ueries$/) correctly matches `jobQueries.update(...)`. Selector 2 (callee.object.property.name=/[Qq]ueries$/) correctly matches `ProfileFCIS.profileQueries.insert(...)`. The ~6 existing hits count is accurate. esquery regex attribute support is confirmed in installed version.
V1 refinement in _findings.md is factually correct — coordinator outbox writes confirmed
.claude/skills/dossier/references/_findings.md:8
All three 'NOT a bug' claims are code-verified: invitation.shells.ts:290 emits core.member.added in-transaction; organization-with-owner.shell.ts:165 emits core.member.added; site-with-devices-provisioning.shells.ts:512 emits core.site.created. The profile case (auth.handler.ts:270,295) has no core.profile.created emission — confirmed real bug, correctly the only V1 violation.
security3
Dynamic import() in cfe-jobs-internal handler bypasses no-restricted-imports entirely
apps/platform/src/api/handlers/cfe-jobs-internal.handler.ts:261
The handler uses `const { jobQueries } = await import('@batu/utility-domain/cfe-job')` at runtime then calls `jobQueries.update(database, ...)` at line 262. ESLint's no-restricted-imports is static analysis only — it cannot see dynamic import() expressions. The import restriction is bypassed entirely. The no-restricted-syntax call-site selector does catch `jobQueries.update(...)` as a warn, but the import gate is silently skipped.
V5 authz divergence (contexts handler enforces member, contract declares admin/owner) — live, unaddressed
apps/platform/src/api/handlers/contexts.handler.ts:97
All five context write operations (create/update/delete context, create/delete relationship) have contract docstrings declaring 'RBAC: Must be admin or owner' but every handler enforces only requireOrgAccess(..., 'member'). Any org member can create/delete contexts. Tracked in _findings.md as V5 (NEEDS-HUMAN) and _canonical-api-form.md, but not addressed in this commit. Context has no FE surface today but the API is callable.
apiKeyQueries.updateLastUsedAt called directly in public API handler — fire-and-forget shell bypass
apps/platform/src/api/handlers/public-v1/auth-token.handler.ts:139
Direct query mutation (.catch() fire-and-forget) in a public API handler. The no-restricted-syntax rule does flag this (starts with 'update') but as warn only. Low stakes for last-used-at tracking, but documents the class of issue the rule is designed to catch.
conventions4
_index.md not updated to reference new audit/ directory
.claude/skills/dossier/references/_index.md
A new references/audit/ directory with 8 files was added but the master index _index.md was not updated. SKILL.md Rule 5 states 'Update _index.md on every Build/Refresh. The index is the discovery surface.' The audit directory is completely undiscoverable from the index.
warn→error promotion references undocumented 'fix-strat' with no ticket or measurable condition
apps/platform/eslint.config.mjs:65
'Promote to error once the fix-strat routes them through shells' — 'fix-strat' exists nowhere in the repo (confirmed by grep). No Linear ticket, no definition of done (zero hits? BAT-269 closed?). The React Compiler rules show the risk: they've been at warn since they landed with the same 'sweep + promote' intent. Add a BAT ticket reference and a concrete measurable condition.
capability-dossier.md (Tier 2 rule) cross-links into Skill internals (Tier 4)
.claude/rules/capability-dossier.md:79
The enforcement footer links to .claude/skills/dossier/references/audit/_canonical-api-form.md — a file inside a Skill (Tier 4, on-demand). Tier 2 rules should be self-contained or reference Tier 1/2 paths; depending on Skill internals creates a fragile cross-tier dependency. If _canonical-api-form.md is intended as a Tier 2 reference it should live in .claude/rules/, not inside a skill's references/audit/ subdirectory.
_audit-index.md uses plain-numeral patterns (1–10) inconsistently with V-prefix taxonomy
.claude/skills/dossier/references/audit/_audit-index.md:21
_findings.md uses V-prefix (V1–V6) per the prior rename from P→V. _audit-index.md introduces 10 canonical patterns with plain numerals only. The taxonomy is inconsistent across two files introduced in the same commit.
tests1
check-freshness.mjs / Mode D was never wired into CI — removal does not weaken gates
.claude/skills/dossier/SKILL.md
Grep across all .github/workflows/ files finds no reference to pnpm dossier:check or check-freshness. The prior pr-checks.yml step described in capability-dossier.md never existed. Removal is a clean docs-only consistency fix — no CI gate was lost.
improvement3
audit/*.md files lack 'snapshot, not living reference' disclaimer
.claude/skills/dossier/references/audit/_audit-index.md
Entity dossiers in entities/*.md are updated via Mode C (Refresh) when the surface changes. The audit/*.md files are one-time Week-1 canonicalization snapshots. There is no prominent header warning that these files are NOT kept current by Mode C. A future agent or reader running a refresh may mistake them for authoritative current-state documents. Add: 'Snapshot: 2026-07-14. Not updated on code changes — consult entity dossier for current state.'
Entity dossier front-matter removal breaks machine-readability without documented replacement
.claude/skills/dossier/references/entities/profile.md
All 8 entity dossiers had contracts: and hooks: YAML front-matter stripped. The audit/*.md files still carry contracts:/shells:/hooks: front-matter (asymmetric). A Mode C refresh agent that previously read entity front-matter to know which files to rescan now has no structured entry point — must parse §1 prose tables. If audit front-matter is the intended machine-readable surface going forward, document this asymmetry so future agents don't look for front-matter in entity dossiers.
_findings.md V1 refinement ('must fire event' not 'must call shell') not reflected in entity dossier §4
.claude/skills/dossier/references/entities/membership.md
Entity dossiers for membership and organization may still describe the shell-call heuristic in §4. The membership dossier's §4 notes 'createMembershipShell has zero callers' as a V1 finding — which _findings.md now says is NOT a violation. Entity §4 sections were not synchronized with the V1 refinement.
History · 7 commits
- 8ff8773needs attentionincremental1H · 3M · 2L2026-07-27 17:46
- 7640070needs attentionincremental10H · 18M · 14L2026-07-18 02:11
- a516a9dneeds attentionincremental4H · 5M · 4L2026-07-17 04:38current
- 910fc6aneeds attentionincremental1H · 9M · 6L2026-07-10 23:48
- 0b75850safeincremental0H · 0M · 0L2026-07-10 23:17
- 380a931safeincremental0H · 0M · 0L2026-07-09 19:17
- 5a9ac90blockedfull5H · 8M · 5L2026-07-07 22:07