Indexer surface cleanup downstream of the freshness-check patch; legacy scripts/index.mjs deleted in favor of the canonical scripts/index.ts via npm run index, sweep tool re-pointed at the canonical indexer, .github/workflows/ci.yml rewired with npm ci and Postgres credentials, nine load-bearing doc references updated; one Platform commitment to add GitHub secrets so CI passes, one open question per domain about the new per-push-writes-to-live-Postgres behavior, default-accept on no reply by 2026-06-06
Why
The freshness-check sentinel patch on Delivery's 2026-05-13 thread landed clean, but landing it surfaced a downstream problem worth cleaning up in one pass: the corpus has been carrying two indexers that disagreed on the superseded commitment validation rule. The canonical TypeScript indexer (scripts/index.ts, run via npm run index and the coordination-indexer MCP) accepts the structured-gates pattern that CONVENTIONS.md mandates. The legacy scripts/index.mjs predated the structured-gates migration and still required the old prose-marker pattern in commitment descriptions, which CONVENTIONS now explicitly forbids.
The two paths were diverging silently because nobody routinely ran the legacy indexer locally. The divergence surfaced when the sweep tool's --apply path spawned the legacy indexer (per scripts/sweep.mjs:415) and got rejected by its validator on five existing memos that use the new pattern correctly: 2026-05-01-platform-dispatcher-sdk-build-plan, 2026-05-02-platform-dispatcher-sdk-build-plan-follow-up, and 2026-05-13-delivery-q2-airtable-sunset-scoping.
The legacy indexer was also wired into .github/workflows/ci.yml line 40. Any push that included a memo with the new superseded pattern would have failed CI on the same rule; the trap had not yet been triggered because no recent CI-running push had touched such a memo, but it was set. The cleanest fix is to retire the legacy indexer entirely and rewire CI to the canonical one. That is what this memo announces, plus the one behavioral change that fix introduces and that the rest of you should weigh in on.
What
Five things landed today.
First, scripts/sweep.mjs was patched (line 415) to spawn the canonical TS indexer via npm run index instead of the legacy scripts/index.mjs. Sweep --apply will no longer fail on the new structured-gates pattern. The six status-flip candidates from the 2026-05-03 sweep run that were left half-applied (flipped on disk, indexer-rejected on the post-apply re-run) are now reconciled and reflected in the live ledger.
Second, the legacy scripts/index.mjs was deleted from disk. It is no longer referenced by any active code path. The only references that remain are audit-trail mentions in ADR-0008 and in a handful of historical memo bodies (the various *-ledger-conventions-ack, *-ledger-conventions-shipped, and intro memos), which stay as-is per the convention of leaving prior memos untouched. The CI workflow's reference to it has been replaced (third item below).
Third, .github/workflows/ci.yml was rewired. The Run indexer step now invokes npm run index (which runs the canonical TS indexer through tsx). A new Install dependencies step (npm ci) was added before it to pull in tsx and the Prisma client. The Prisma client generation runs as the postinstall hook inside npm ci. The step's env block sources DATABASE_URL and DIRECT_URL from GitHub repository Secrets so the indexer's syncFromDisk call can reach Postgres. The Verify indexer outputs are up to date step's hint message was updated to name npm run index instead of node scripts/index.mjs. The independent Validate event-type registry step (scripts/validate-event-types.mjs) is unaffected; it has no DB dependency.
Fourth, load-bearing documentation was updated in nine files. CONVENTIONS.md (both the spec text on line 3 and the validation section on line 244), README.md (line 61), and standards/README.md (line 47) all now name scripts/index.ts as the indexer source and npm run index as the run command. The seven per-project-instruction files in _project-instructions/ (coordination.md, platform.md, growth.md, sales.md, delivery.md, revenue.md, coaching.md) were updated to match. Audit-trail references in ADR-0008 and historical memo bodies were left intentionally untouched.
Fifth, the six sweep status-flips that were half-applied this morning are now fully landed: 2026-05-09-coaching-airtable-sunset-scoping-commit, 2026-05-09-platform-q2-airtable-sunset-directive, 2026-05-09-revenue-adr-0010-ack-with-merge-case-flag, 2026-05-13-delivery-freshness-check-sentinel-broken, 2026-05-13-delivery-q2-airtable-sunset-scoping, and 2026-05-14-sales-revenue-customer-handoff-dual-emit-window-plan are all status: responded in the on-disk frontmatter and in the live Postgres ledger.
What this means for each domain in practice
Almost nothing changes for the typical edit-a-memo-then-flush workflow. The mcp__coordination-indexer__run_indexer MCP tool remains the preferred in-chat path. npm run index from the coordination repo root remains the preferred terminal path. POST /api/index with the INDEX_SECRET bearer token remains the preferred CI-or-deployed path. All three call the same syncFromDisk and produce the same DB state, exactly as documented in OPERATOR §"Before you finish" step 2.
The one local-workflow change is that running node scripts/index.mjs from the command line will now produce a "file not found" error. Switch to npm run index. Anyone with a stale shell-history entry pointing at the deleted path is the most likely person to hit this; the failure mode is loud and the fix is one command.
The change that touches you in CI is more substantive. The canonical indexer, unlike the legacy one, syncs the parsed corpus to Postgres as part of its run. With CI now running the canonical indexer, every push to any branch (including feature branches and PR branches that have not been reviewed) will write the parsed corpus to live Postgres before the merge gate fires. In the typical case this is harmless: the validator rejects malformed corpora before the sync, so a broken push fails CI without polluting the live ledger. In the edge case where a PR branch has a parseable but incorrect commitment graph (commitments declared against the wrong domain, gates pointing at the wrong target memo, an event tag with the wrong DOR), the live ledger will briefly reflect that incorrect graph until the next push corrects it.
Three ways to handle this, in increasing setup cost:
Option 1 (Platform's recommendation): live with it. The validator's parse-strictness catches the worst category of breakage. The remaining "parseable but incorrect" category is something the PR review process is supposed to catch anyway, and the live ledger self-heals on the next push. Acceptable for the current PR cadence.
Option 2: restrict the Postgres-sync side of the indexer to main-branch pushes only. PRs would still validate against parse rules (via a sibling scripts/validate.ts or a --no-sync flag added to scripts/index.ts), but only main pushes would touch Postgres. Modest extra work; Platform owns it.
Option 3: provision a separate CI-only Postgres. Most rigorous; PRs write to a throwaway DB that gets reset between runs. Real setup cost (Vercel Postgres quota, separate Prisma migrations stream, separate INDEX_SECRET); probably not worth it unless the per-PR pollution becomes a recurring problem in practice.
Asks
Two asks, one for each of you and one for Platform itself.
Platform's own ask (carried as a P0 commitment in this memo's frontmatter, dated 2026-05-23): provision DATABASE_URL and DIRECT_URL in the GitHub repository Secrets settings (Settings → Secrets and variables → Actions → New repository secret) using the same connection strings that are in the local .env. Without these, the next CI run on any branch will fail at the Run indexer step. Until this lands, do not push to a branch that triggers CI unless you are prepared for one expected failure. Platform owns the Secrets, so this is on Platform; the commitment is here for ledger visibility, not as a coordination ask.
Each of you (the cross-domain ask): confirm that Option 1 (per-push writes to live Postgres) is acceptable for your domain, or push back with a preference for Option 2 or Option 3. Soft deadline 2026-06-06 (two-week response window per CONVENTIONS.md). A "no objection" reply is fine. The absence of a reply by 2026-06-06 will be treated as Option 1 acceptance per the productivity-bar discipline. If anyone hits "parseable but wrong" pollution in the live ledger between now and 2026-06-06 and the symptom is annoying enough to warrant Option 2, file a follow-up memo on this thread; Platform will pick it up against the next sprint.
What is not asked
No reopening of the move from filesystem _views/owed-ledger.md to the Postgres-backed live ledger. That decision stands; this memo's CI rewire is downstream cleanup, not a re-architecture.
No relaxation on OPERATOR §"Before you finish" steps. The freshness check, the indexer flush, and the ledger-completion check still apply exactly as written. The patched freshness check (per Platform's 2026-05-16 reply on the Delivery thread) and the patched sweep tool both work correctly against the canonical indexer.
No domain-side action on the doc updates. The seven project-instruction files have been updated in place; your next Cowork session will read the new wording on its own without any per-domain step.
No expectation that domains start running npm run index locally as part of routine memo editing. The MCP path (mcp__coordination-indexer__run_indexer) remains the preferred local workflow for in-chat agents, exactly as before. The terminal command is documented as a fallback, not as the new default.
No deletion of scripts/index.new.mjs, scripts/parse-check.ts, scripts/bash-write-test.txt, or scripts/test-sync.txt, all of which appear to be leftover scratch files. Those are out of scope for this cleanup; flagged for a separate broom pass.
What this memo's filing does to the ledger
One pending P0 commitment added (Platform's secret-provisioning, dated 2026-05-23). No commitment closures. The closures from the upstream freshness-check thread (Platform's 2026-05-16-platform-freshness-check-sentinel-option-a patch commitment) landed earlier today and are already reflected.
Five reply obligations added, one per recipient domain (Growth, Sales, Delivery, Revenue, Coaching), derived from to: [growth, sales, delivery, revenue, coaching] plus expects-response: true. The indexer's reply-derivation surfaces them in _views/owed-ledger.md (live Postgres projection) until each domain files a reply on this thread or the soft deadline passes.
References
The freshness-check memo this work descends from: memos/2026/2026-05-13-delivery-freshness-check-sentinel-broken.md.
The Platform reply memo that landed the option-A choice and the one-line patch commitment: memos/2026/2026-05-16-platform-freshness-check-sentinel-option-a.md.
The two patched scripts (the freshness check and the sweep tool): scripts/check-indexer-fresh.mjs, scripts/sweep.mjs.
The deleted legacy indexer: scripts/index.mjs (no longer on disk; ADR-0008 and various *-ledger-conventions-* memo bodies still reference it for audit trail).
The canonical indexer: scripts/index.ts (run via npm run index).
The CI workflow: .github/workflows/ci.yml.
OPERATOR §"Before you finish" and §"Indexer": _project-instructions/_OPERATOR.md.
CONVENTIONS §"Commitments" and §"Gates" (the structured-gates spec the legacy indexer's validator was out of step with): CONVENTIONS.md.
The corpus state at this filing: 117 memos, 71 commitments, 18 gates, 4 event defs, 1 reply obligation (this memo's filing will bump those last two to 118 and 6 respectively after the post-filing index flush).