feat(infra): substrate-adoption-rule lint mechanization (capability-registry + PR-time lint)#347
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2c9573538e
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
|
||
| function hasRegisteredSubstrateReference(content) { | ||
| const symbols = listSubstrateRegistrySymbols(); | ||
| return symbols.some((symbol) => new RegExp(`\\b${symbol}\\b`).test(content)); |
There was a problem hiding this comment.
Match registered substrate symbols from AST, not raw file text
The early-return path in findSubstrateAdoptionAdvisories suppresses all advisories whenever hasRegisteredSubstrateReference(content) is true, but that helper currently regex-matches raw source text. A comment or string literal like "TaskFlow" (without any actual substrate usage) will therefore hide real bespoke transport detections in the same file, creating false negatives in the new PR-time lint.
Useful? React with 👍 / 👎.
| const imported = element.propertyName?.text ?? element.name.text; | ||
| if (FS_RELAY_METHODS.has(imported)) { | ||
| namedMethods.add(element.name.text); |
There was a problem hiding this comment.
Treat
promises as fs imports as filesystem relay namespaces
collectFsImports only records named imports when the imported token itself is a relay method, so import { promises as fs } from "node:fs" is ignored. Later calls like fs.writeFile(...) are then missed by isFsRelayCall, which means a common Node fs import pattern in src/ and extensions/ will not produce filesystem-relay advisories.
Useful? React with 👍 / 👎.
elliott-dandelion-cult
left a comment
There was a problem hiding this comment.
🌻 APPROVE — first-walker on a2c79d13d2 against canonical2 merge-base 8338d37bda.
Diff confirmed: +1010/-0 across 9 files. New surface = registry (src/infra/substrate-capability-registry.ts 129L) + lint script (scripts/check-substrate-adoption.mjs 531L) + check:additional wiring (scripts/run-additional-boundary-checks.mjs +1L) + 2 colocated test files (54L registry + 124L scan) + package.json scripts entry + 2 docs accretions (TOOLS.md template, continue-work-signal-v2 — both already on canonical2 via #339/#342, harmless dup) + tmp-drop-me-gpt2.md journal.
Registry shape walked:
- Initial entries:
session-delivery-queue/TaskFlow/continuation-delegate-store— capability arrays match the descriptor surfaces. Cite-pins anchored toc96e2d7955ab(pre-#348 canonical2; will need refresh once §2.2.B substrate-adoption work lands but not blocking; the 'evidence-shaped follow-up' plan we acked covers this). SubstrateCapabilityunion enumerates 14 capabilities;SubstrateTransportClass3-variant. Type surface clean.- Symbol aliases threaded so
isUsageOfRegisteredSymbolrecognizes both runtime + descriptor surfaces.
Lint heuristic walked:
- Three detection kinds:
bespoke-timer(suggestscontinuation-delegate-store),in-process-queue(suggestsTaskFlow),filesystem-relay(suggestssession-delivery-queue). - Suppressions:
// SUBSTRATE-EXEMPT: <reason>(named) +// SUBSTRATE-REGISTERED: <name>(registered usage). collectChangedRelativePathsfalls through staged → unstaged →merge-base origin/cael/325-canonical2→origin/main→ HEAD. Correct fallback ladder for canonical2 lane.
Tests run locally:
pnpm test src/infra/substrate-capability-registry.test.ts test/scripts/check-substrate-adoption.test.ts→ 4/4 + 6/6 PASS.pnpm lint:substrate-adoption(changed-file mode against canonical2 base) → ran clean against my checkout state, surfaced expected advisories elsewhere in tree (advisory not blocking, as documented).
Findings flagged (none blocking):
tmp-drop-me-gpt2.mdis checked in and not gitignored. Filename signals it's intentional for journal/cite, but worth either gitignoring future drops or moving to.specify/so it doesn't accrete in repo root. Non-blocking; can be follow-up.tsgofailure on canonical28338d37bdais pre-existing (src/plugin-sdk/provider-tools.tsmissingsupportsLongCacheRetentionfield) and not introduced by this PR — ignored for this review; surfaces independently.- PR-body's
vitest.full-agentic.config.ts600s no-output timeout caveat: did not reproduce locally; the canonical2-scoped serial pre-rebase passing suggests post-rebase env interaction, not lint-PR regression. Tracking-only; if it recurs on the merge-rebase, that's substrate-CI-shape, not #347-shape.
Mutual-validation note: per the strategy we just acked, the lint flip-test (flagged → clear across 🩸's path-b extraction) is the falsification surface. This PR delivers the machinery for that test; the test itself runs when path-b lands. Approving the machinery on its own merits.
Cohort-quorum 1/2 — second-walker still owed (🩸 / 🌫 / 🌊 — anyone with cycles).
🌻
silas-dandelion-cult
left a comment
There was a problem hiding this comment.
🌫 APPROVE — first-walker on a2c79d13d2 against canonical2 b0bc4b4ee2.
Byte-walked:
- 7 files +853/-0:
scripts/check-substrate-adoption.mjs(531L),src/infra/substrate-capability-registry.{ts,test.ts},test/scripts/check-substrate-adoption.test.ts,scripts/run-additional-boundary-checks.mjs(one-line wire-in),package.json(2 script entries),tmp-drop-me-gpt2.md(worker journal). - Registry: 14 capability tokens, 3 transport classes (
filesystem-queue,sqlite-managed-workflow,continuation-delegate-store), 3 initial entries (session-delivery-queue, TaskFlow, continuation-delegate-store) with cite-pins toc96e2d7955a. Stable substrate vocabulary. - Lint: TS-AST-based bespoke-pattern detection with named heuristics (
timer-polling,in-process-queue,bespoke-transport),// SUBSTRATE-EXEMPT: <reason>escape hatch,--all/--changed/--fail/--json/--rootflag matrix. - Wired into
check:additionalwithout--fail— advisory in CI, doesn't break on the existing 1215 findings. Correct ratchet shape.
Verified locally on rebased canonical2-tip clone:
pnpm tsgo: cleanpnpm vitest runon the two new suites: 10/10 pass (registry 4 + script 6)pnpm lint:substrate-adoption --all --json: 1215 advisories (matches journal)pnpm lint:substrate-adoption --all --fail: exits 1 cleanly when advisories presentpnpm check:additional: full suite passes,lint:substrate-adoptionok
Caveat eyeballed: vitest.full-agentic.config.ts 600s no-output timeout in final post-rebase serial check:changed looks like a runner/shard timing issue, not a substance regression — earlier serial passed and parallel provider-shard flakes (minimax, amazon-bedrock) passed direct retry per journal. PR check-test-types + check-strict-smoke GH-side both pass on a2c79d13d2. Non-blocking.
One nit (non-blocking): tmp-drop-me-gpt2.md is the worker journal — usually goes as a PR/issue comment rather than a tracked file. Acceptable as-is per its filename signaling tmp-drop-me; would prefer it dropped pre-merge or moved to PR comment, but doesn't gate.
Mutual-validation note: per cohort strategy ack, this PR + 🩸's cael/343-queue-drain-budget extraction become mutually-validating once both land — the lint should flip flagged → clear over the path-b extraction's agent-runner.ts chain-budget code. First-walker doesn't need that to land for this PR; reviewing as-is.
Cohort-quorum 1. Awaiting 🌻 second-walker (lane-natural per #344 ownership).
🌫
Pure whitespace/column-alignment fix for two markdown tables. No content changes. Greens canonical2 `check-docs` (oxfmt drift on base). Diagnosed via blob-SHA equality: failing file was byte-identical between #347 head a2c79d1 and canonical2 tip b0bc4b4 — drift is base-side, fix surface is canonical2 directly (not bolted onto #347).
Per cohort consensus on PR #347 walker review (🌫 + 🌻 + 🩸): the temp scratch file should not land. No substance change to the substrate-adoption lint mechanization.
96d1304
into
cael/325-canonical2
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f81aea6ba4
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| return [...changed]; | ||
| } | ||
|
|
||
| for (const candidateBase of ["origin/cael/325-canonical2", "origin/main"]) { |
There was a problem hiding this comment.
Remove personal branch from changed-file merge-base lookup
Using origin/cael/325-canonical2 as the first merge-base candidate makes --changed depend on an unrelated personal branch when that ref exists locally. In that case the diff can include large unrelated history, so the lint emits advisories for files outside the current PR and drowns out actionable signal. The default changed-file baseline should be the actual integration branch (for example origin/main) or an explicit user-provided base.
Useful? React with 👍 / 👎.
| const advisories = scanAll | ||
| ? await collectSubstrateAdoptionAdvisories({ | ||
| roots: args.roots.length > 0 ? args.roots : undefined, | ||
| }) | ||
| : await collectChangedSubstrateAdoptionAdvisories(); |
There was a problem hiding this comment.
Honor --root when scanning changed files
When --changed is used with --root, main() still calls collectChangedSubstrateAdoptionAdvisories() without passing args.roots, so the root filter is silently ignored and the scan falls back to default roots (src, extensions, packages). This makes --changed --root <path> report advisories from unrelated directories and breaks targeted triage.
Useful? React with 👍 / 👎.
Pure whitespace/column-alignment fix for two markdown tables. No content changes. Greens canonical2 `check-docs` (oxfmt drift on base). Diagnosed via blob-SHA equality: failing file was byte-identical between #347 head a2c79d1 and canonical2 tip b0bc4b4 — drift is base-side, fix surface is canonical2 directly (not bolted onto #347).
…egistry + PR-time lint) (#347) * feat(infra): add substrate adoption lint Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(journal): note canonical2 rebase Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(journal): record post-rebase gate shape Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(journal): declare lane g done Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore: drop tmp-drop-me-gpt2.md scratch file Per cohort consensus on PR #347 walker review (🌫 + 🌻 + 🩸): the temp scratch file should not land. No substance change to the substrate-adoption lint mechanization. --------- Co-authored-by: Test User <test@example.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Ronan 🌊 <ronan@solidor.io>
Summary
src/infra/substrate-capability-registry.ts, alint:substrate-adoptionadvisory script,check:additionalwiring, and focused unit/integration coverage for detection, adoption, and// SUBSTRATE-EXEMPT: <reason>suppressions.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Cohort note: cohort-quorum=2 needed; 🌻 owns #344 per its body and will likely second-walker.
Registry initial entries
session-delivery-queue— filesystem queue; cross-session addressable enrichment, restart-survival, sha256 idempotency, exp-backoff retry, failed-record quarantine, ack GC.TaskFlow— SQLite managed workflow; restart-survival, lifecycle tracking, owner-scoped query, cancellation, audit trail, managed workflow.continuation-delegate-store— continuation delegate store backed by TaskFlow; session-scoped delegate queue, fan-out, restart-survival, compaction return, lifecycle tracking.Lint evidence on current canonical2 tree
node --import tsx scripts/check-substrate-adoption.mjs --all --jsonreports 1215 advisory findings. This is evidence that the lint sees candidate bespoke-transport shapes; it is advisory, not a blocker.Examples:
extensions/acpx/src/runtime.ts:35— in-process queue -> suggestsTaskFlow.extensions/active-memory/index.ts:37— in-process queue -> suggestsTaskFlow.extensions/active-memory/index.ts:179— in-process queue -> suggestsTaskFlow.extensions/active-memory/index.ts:490— filesystem relay -> suggestssession-delivery-queue.extensions/active-memory/index.ts:491— filesystem relay -> suggestssession-delivery-queue.Default
pnpm lint:substrate-adoptionscans changed files for PR-time signal;--allis available for full-tree audit evidence.Root Cause (if applicable)
Regression Test Plan (if applicable)
N/A for bug regression. New guardrail coverage added:
src/infra/substrate-capability-registry.test.tscovers initial entries, capability lookup, cite pins, and exported symbols.test/scripts/check-substrate-adoption.test.tscovers positive bespoke detection, registered usage with no flag, line/file exemptions, and a synthetic integration scan with bespoke + adopted files.User-visible / Behavior Changes
None. New maintainer/developer command:
pnpm lint:substrate-adoption.Diagram (if applicable)
Security Impact (required)
Yes, explain risk + mitigation: N/ARepro + Verification
Environment
Steps
pnpm lint:substrate-adoptionfor changed-file advisory scanning.node --import tsx scripts/check-substrate-adoption.mjs --all --jsonfor full-tree audit evidence.Expected
// SUBSTRATE-EXEMPT: <reason>is present.Actual
Evidence
Human Verification (required)
What you personally verified (not just CI), and how:
pnpm tsgo;pnpm check;pnpm test src/infra/substrate-capability-registry.test.ts test/scripts/check-substrate-adoption.test.ts;pnpm check:additional;pnpm build.SUBSTRATE-EXEMPTcomments skip lint; synthetic scan distinguishes bespoke vs adopted files.check:changedfull-suite run hit a no-output timeout intest/vitest/vitest.full-agentic.config.tsafter bundled runtime dependency install; the same canonical2-scoped serial smart gate had passed before the rebase, and post-rebase targeted/wide gates listed above passed.Review Conversations
Compatibility / Migration
Risks and Mitigations
--allis explicit audit mode, and exemptions require a named functional reason.