Skip to content

ci(graph): assert named entrypoints in graph preflight presets - #338

Merged
imjlk merged 3 commits into
mainfrom
claude/graph-preflight-named-entrypoints
Oct 11, 2026
Merged

imjlk merged 3 commits into
mainfrom
claude/graph-preflight-named-entrypoints

Conversation

@imjlk

@imjlk imjlk commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

Summary

pnpm graph:preflight (run in the build-web-targets CI job) used to require that each ttsc-graph tour's anchors start with a directory prefix (expectedFiles). The tour ranking is a heuristic over the whole graph, so unrelated feature PRs shifted it: #264 folded a packages/game-services module back into an existing file to keep tools/target/ anchored, and #337 added an executeNativeTargetBuild hint to target-release.json for the same reason.

This PR replaces the directory-prefix check with a named-entrypoint contract:

  • Every preset declares namedEntrypoints: [{ name, file, kind? }], the symbols its question is about. For tour presets the runtime derives request.reinterpretations from that list (checked-in presets no longer write the field; an explicit field is accepted only if it equals the derived list), so the names the tour seeds and the names the preflight asserts are one list. Details presets derive the list (kind included) from their pinned file#name:kind handles.
  • tools/graph/local-graph-runtime.mjs gains graphResultSymbols / missingNamedEntrypoints / assertGraphPresetResponse: a named entrypoint is satisfied only by a graph node id in the result whose file and symbol name match (searched across tour entrypoints, flow starts, flow reached nodes, id-bearing anchors, and details nodes). Edge anchors such as calls foo (no id, call-site file) and same-named symbols in other files do not count. Paths normalize \ and leading ./.
  • tools/graph/run-graph-presets.mjs keeps the next.action === 'answer' and non-zero anchor checks and reports the missing symbols and files by name. expectedFiles is removed (rejected with a migration message) rather than kept as a secondary check; the file header documents why.
  • The old 14-22 item hint lists are gone: extra hints competed with the named symbols for the tour's named seeds (the library caps a tour at five seeds and gives names half of them), which is what made bootstrapStarter, createGameServicesBackend, and withTargetAvailability drop out while they were present. Deriving the seed list from namedEntrypoints removes that failure mode by construction.
  • Ad-hoc pnpm graph:inspect --request files stay lenient: namedEntrypoints is optional and bare-name details handles are skipped rather than rejected; only checked-in presets are asserted.
  • Test-file anchoring is not asserted (the i18n-locale-resolution preset previously listed packages/i18n/test/i18n-smoke.ts in expectedFiles); tours cite tests through their own test-coverage anchors, and the preset description and README say so.
  • New tools/graph/README.md explains presets, the rule, how to add a preset, and why feature PRs must not edit presets to make preflight pass; docs/TTSC_TOOLCHAIN.md links to it.

Rule

A preset passes when the graph answer is answer-ready, has anchors, and cites every namedEntrypoints entry by file and symbol name. Feature PRs must not edit presets to make preflight pass; a failing preflight means a named entrypoint was renamed/moved/removed (update the preset in the same PR as the rename) or its name became ambiguous in the graph.

Per-preset named entrypoints:

Preset Named entrypoints
target-release executeNativeTargetBuild (tools/target/native-build-execution.ts), validatePlatformTargetsFile (tools/target/validate-platform-targets.ts), generateReleaseManifest (tools/target/generate-release-manifest.ts), verifyTargetArtifacts (tools/smoke/verify-target-artifacts.ts)
bridge-contracts assertBridgeRequest, assertBridgeResponse (packages/bridge/src/index.ts), parseBridgeRequest (adapters/ait/src/host.ts)
package-publish discoverBuildablePackages, sortByWorkspaceDependencies (tools/package/workspace.ts), selectBuildablePackages (tools/package/build-packages.ts), npmPackDryRun (tools/package/pack-packages.ts)
i18n-locale-resolution readMpgdPreferredLocales, resolveTargetMpgdLocale, normalizeMpgdLocale (packages/i18n/src/index.ts)
starter-loop (cwd examples/phaser-starter) bootstrapStarter (src/bootstrap.ts), installStarterPlatform (src/platform/installStarterPlatform.ts), createStarterGame (src/runtime/createGame.ts), createStarterGameServices (src/platform/gameServices.ts)
target-config-runtime withTargetAvailability, createTargetRuntimeSnapshot (packages/target-config/src/runtime.ts), createEffectiveTargetConfigMatrix (packages/target-config/src/effective.ts), validateEffectiveTargetConfigMatrix (tools/target/effective-config.ts), generateEffectiveTargetConfigArtifacts (tools/target/generate-effective-target-config.ts)
game-services-backend (worker tsconfig) createGameServicesRouter, createGameServicesBackend (packages/game-services/src/server.ts), createWorkerFetchHandler (apps/game-services-worker/src/handler.ts), createD1GameServicesStore (apps/game-services-worker/src/d1Store.ts)
game-services-contract, tutorial-core, tutorial-driver derived from their details handles

Test plan

  • pnpm graph:preflight on the clean tree: all 10 presets pass.
  • Drift simulation: temporarily appended an exported createDriftSimulationGameServicesBackend to packages/game-services/src/server.ts, ran pnpm graph:preflight — all 10 presets still passed (exit 0), including game-services-backend and game-services-contract whose graph the new export changed — then reverted the simulation (not committed).
  • pnpm test:tooling (40 tests, including the new tools/graph/run-graph-presets.test.mjs: synthetic tour whose ranked anchors all drifted into packages/cli passes while the named entrypoints are cited; fails naming generateReleaseManifest (tools/target/generate-release-manifest.ts) when absent; edge anchors without ids and same-name symbols in other files do not satisfy; Windows separators / ./ / ../; details handle derivation incl. kind; ad-hoc bare-name handles; derived vs. explicit reinterpretations; every checked-in preset's named entrypoints are declared on disk, with checked-in tours carrying no reinterpretations field).
  • Round 2 (after review): pnpm graph:preflight 10/10 again on the derived-seed presets; captured-dump re-check 10/10; declaration-regex probe (13 cases: export type {}, from re-exports, as aliases, multi-line lists).
  • pnpm docs:evidence
  • pnpm format (no drift in untouched files); node --check on the .mjs files.

No changeset: CI tooling, docs, and private preset files only; no publishable package changes.

Local review

A reviewer subagent (sonnet) went over the working-tree diff for false passes, brittle matching, and Windows paths. Findings applied:

  • False pass through nested ids (bug): the symbol walker descended into details nodes[].calls/types and ambiguous[].candidates, so an unresolved handle could count as cited. The collector is now shape-aware: only the result's answer surface (tour entrypoints, flow starts/reached, id-bearing anchors; details nodes; trace start/reached) and only each entry's own id. Test added.
  • name-field fallback loosened member matching (bug): a trace node's simple name could satisfy member for any Owner.member. Matching is now the id's symbol part only. Test added with a simple-name trace node.
  • Optional kind: entries may pin a node kind; details-derived entries carry the handle's kind. Test added.
  • Path normalization: normalizeGraphFile now trims and runs path.posix.normalize (handles ./, a/../b, //; keeps ../../ for cwd-scoped graphs). Both preset and result sides go through it.
  • inspect-local-graph.mjs --request regression: ad-hoc request files no longer need namedEntrypoints (readRequestFile is lenient; readPreset strict; the preflight refuses a preset that asserts nothing). Test added.
  • On-disk test uses a declaration regex instead of includes; dead graphResultFiles export removed; README softened on how reliably tours cite seeded names and now states that checked-in tour presets list exactly their named entrypoints (enforced by the test).

Not applied: capping tour presets at three named entrypoints (the five in target-config-runtime all land, confirmed on the clean tree and in the drift simulation; the README asks authors to verify each name with pnpm graph:preflight).

Round 2 (pre-merge review, 6 items): (1) ad-hoc details files with bare-name handles no longer throw — fixed, test added; (2) reinterpretations duplication — fixed by deriving it from namedEntrypoints and dropping the field from checked-in presets; (3) matchesNamedEntrypoint compares normalized fields directly; (4) i18n test anchor — documented as not asserted (test variable names are neither stable nor seedable); (5) declaration regex widened to export {} lists / function*, but re-exports and alias targets are excluded since the graph cites the declaring file; (6) comment added on the internal @ttsc/graph requires. A second sonnet pre-push review of that delta found no bugs; its robustness items were applied (duplicate names seed once, ad-hoc explicit lists validated and trimmed, ad-hoc namedEntrypoints: [] tolerated, clearer empty-handles message, assertGraphPresetResponse documents that it expects normalizeRequest output).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Improvements

    • Graph preset results are now checked for citations to each required symbol, helping ensure answers include the requested source references.
    • Graph requests identify specific symbols rather than relying on broad directory matches.
  • Documentation

    • Added guidance on running graph presets, naming entrypoints, and understanding validation results.

Replace the directory-prefix `expectedFiles` check in
tools/graph/run-graph-presets.mjs with a per-preset `namedEntrypoints`
contract matched by file and symbol name against the graph result's answer
surface. Tour presets seed the same names through `reinterpretations`,
details presets derive the list from their handles. Add a drift-simulation
test, document the rule in tools/graph/README.md, and link it from
docs/TTSC_TOOLCHAIN.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 0e6e9449-cd71-4157-9d3c-d1c25951cf6f

📥 Commits

Reviewing files that changed from the base of the PR and between 58b313c and 36f78c9.


📒 Files selected for processing (17)
  • docs/TTSC_TOOLCHAIN.md
  • package.json
  • tools/graph-runtime.test.mjs
  • tools/graph/README.md
  • tools/graph/local-graph-runtime.mjs
  • tools/graph/requests/bridge-contracts.json
  • tools/graph/requests/game-services-backend.json
  • tools/graph/requests/game-services-contract.json
  • tools/graph/requests/i18n-locale-resolution.json
  • tools/graph/requests/package-publish.json
  • tools/graph/requests/starter-loop.json
  • tools/graph/requests/target-config-runtime.json
  • tools/graph/requests/target-release.json
  • tools/graph/requests/tutorial-core.json
  • tools/graph/requests/tutorial-driver.json
  • tools/graph/run-graph-presets.mjs
  • tools/graph/run-graph-presets.test.mjs

💤 Files with no reviewable changes (3)
  • tools/graph/requests/tutorial-driver.json
  • tools/graph/requests/tutorial-core.json
  • tools/graph/requests/game-services-contract.json

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.



📝 Walkthrough

Walkthrough

Graph presets now declare named entrypoints by file and symbol. Request normalization derives tour reinterpretations from those declarations, and preflight verifies that answer-ready results cite every required entrypoint. Tests and documentation cover the updated contract.

Changes

Graph preset entrypoint validation

Layer / File(s) Summary
Normalize requests and declare entrypoints
tools/graph/local-graph-runtime.mjs, tools/graph/requests/*
Request normalization validates or derives named entrypoints and derives tour reinterpretations from their names. Checked-in requests replace expectedFiles and stored reinterpretation lists with named entrypoints.
Match cited symbols and validate responses
tools/graph/local-graph-runtime.mjs, tools/graph/run-graph-presets.mjs
Response validation extracts symbols from answer surfaces and matches their normalized file and symbol names to declared entrypoints. The preset runner delegates validation to this helper.
Test and document the entrypoint contract
tools/graph/run-graph-presets.test.mjs, tools/graph-runtime.test.mjs, package.json, tools/graph/README.md, docs/TTSC_TOOLCHAIN.md
Tests cover entrypoint matching, request normalization, and response validation. Tooling documentation describes the contract, and test:tooling runs the new preset tests.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix


Merge Risk: ⚪ Minimal · up to 36f78

No actionable merge-blocking issue remains after the normal checks.

Pre-merge checks | Passed 4 | Failed 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 52.63% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 4 files. (10 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check Passed The title clearly identifies the primary change: asserting named entrypoints in graph preflight presets.
Description check Passed The description includes the required Summary, Validation, and Notes information. It documents the implementation, test results, scope, and validation commands in detail.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.

Full details: Docstring Coverage

Explanation

Docstring coverage is 52.63% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 4 files. (10 skipped: 10 unsupported.)


  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR


🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit checks each cited name,
Then follows paths that match the same.
The presets list each symbol clear,
The tests confirm the answers here.
I twitch my nose and hop away.

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-11T16:09:52.898137Z 8b74983 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

imjlk and others added 2 commits October 12, 2026 01:16
… checks

Address pre-merge review of #338:

- Tour presets no longer write request.reinterpretations; normalizeRequest
  derives it from namedEntrypoints (an explicit field must equal the derived
  list), so the asserted list and the seeded list are one list.
- Ad-hoc --request details files may use bare-name handles; they are skipped
  instead of throwing. Checked-in presets still must pin file#name:kind ids.
- matchesNamedEntrypoint compares already-normalized fields; the on-disk
  declaration test accepts export lists but not re-exports or alias targets.
- Note that test-file anchoring is not asserted (i18n preset description and
  README) and that the @ttsc/graph internal requires must be re-checked on
  version bumps.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
rspress serves docs/ as the site root and treats ../tools/graph/README.md
as a dead link; use the repository blob URL like the other out-of-site
references.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@imjlk
imjlk merged commit 757ebce into main Oct 11, 2026
16 checks passed
@imjlk
imjlk deleted the claude/graph-preflight-named-entrypoints branch October 27, 2026 11:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant