Skip to content

v1.221-developer-rails — modules/capabilities/sessions rail rebuild + residual closeout - #445

Merged
auto-wood merged 22 commits into
mainfrom
iteration/v1.221-developer-rails
Oct 24, 2026
Merged

auto-wood merged 22 commits into
mainfrom
iteration/v1.221-developer-rails

Conversation

@auto-wood

Copy link
Copy Markdown
Contributor

Summary

Completes the developer rail registry (操作台 / Harness / 模块 / 能力 / 会话) under the 2026-10-22 web-rebuild authorization. Three plans, each SDD-implemented with tri-QC + mandatory QA, serially merged to the integration branch:

  • v221-modules-rail (885d8d5ca): /modules becomes a first-class rail app — Settings-modal ownership deleted outright (section, canonicalization, entrance row, modal-primary takeover; no redirect per product decision), page body migrated into components/developer/ with the pure-view chrome split (modules-page-chrome + run-studio-chrome), Run Studio + all deep links (?module=&run=, ?world=&branch=) preserved, Studio fixture (5 variants, both themes), locale-parity, zero /settings/modules residue.
  • v221-caps-sessions-rail (40703cc55): capabilities + sessions lifted to the same generation — capabilities chrome split with locked copy decisions (registry-empty vs filtered-miss, Clear filter) and ?filter= deep link intact; sessions table rebuilt as hub-card cards (field set per SessionSummary, whole-card link to run view, statusVariant reused as-is, F-F1 order pinned by DOM-order equality), fixtures + locale parity.
  • v221-web-residuals (abaccf2f3): I-000058 trailing-space fold tripwire (fails-first verified) + discovery-lifecycle green (comment fix, assertion semantics intact).

Post-QC fixes: Q3-01 dead RunStudioCopy props (4990fb08), QC3-R-1 duplicate filter input ids → useId() with negative-checked fixture test + QC3-R-2 (8bde1044). Close commit adds the thrice-verified rail-app rebuild recipe to knowledge.

Verification

  • Targeted vitest across modules/caps/sessions/hub-card/locale-parity/registry/entrance/deep-link suites, design-studio fixture + App tests, web + design-studio typechecks — all green at each merge.
  • QC tri 3/3 PASS per plan; mandatory QA PASS per plan; findings mode allow-residual with disclosures in each plan's qc-consolidated.md / qa-report.md.
  • Tracking issue opened: I-000084 (Advanced-JSON disclosure open-state assertion).

Test plan

  • pnpm --filter web typecheck + pnpm --filter design-studio typecheck
  • Targeted vitest suites per plan (see .mstar/sdd/v221-*/review/qa-report.md evidence)
  • CI

…-000058)

The refusal folds case and per-segment trailing dots AND spaces, but only
the dot half had a regression tripwire. Add `/v1%20/y` to the HTTP fold
matrix (404 not_found, non-INDEX body, nosniff) and `v1 /x` to the
unit-seam traversal array.

Verified as a tripwire: narrowing the fold regex to `[.]+$` turns exactly
these two cases red and leaves the existing fold cases green.
Remove the Settings-modal ownership of the modules section: drop the
section id/descriptor/aliases, the develop nav item and route rule, the
modal section wrapper, and the locale key. ModulesPage renders the page
body instead of redirecting; canvas/timeline Run Studio entries navigate
to /modules directly. Settings tests, the timeline compute journeys and
the Design Studio fixture are rebased on the page contract.
…presentational chrome

- components/developer/modules-page.tsx keeps the app wiring (queries, deep-link
  router reads, copy assembly); pages/modules-page.tsx is deleted
- presentational/modules-page-chrome.tsx: ModulesPageChrome + ModuleDetailChrome
  (+ DetailField, SchemaBlock), pure view with a runStudio slot
- presentational/run-studio-chrome.tsx: RunStudioChrome, pure view driven by
  copy/world/form/advanced/run/proposal/runs view models
- compute/run-studio.tsx keeps every hook, mutation, toast and the two confirm
  dialogs; public props unchanged, canvas entry untouched
- app-registry modules.load → the new page
- close T1 residuals F1-F5 (stale SSOT/section comments, dead shell.nav.modules
  locale key, unexported dead SettingsModalContext)
…t alias

- fixtures/modules-rail-fixtures.tsx: ModulesPageChrome + ModuleDetailChrome +
  RunStudioChrome from static view models and literal copy (list with one
  selected, manifest detail beside the select prompt, run pending/success/
  detail-error); theme follows the Studio toggle
- fixtures/__tests__/modules-rail-fixtures.test.tsx: one assertion per variant
  testid plus a both-theme render smoke
- @web-developer alias in tsconfig + vite + vitest (Studio resolves every
  @Web-* extract through all three)
- surface-source-badge: classify @web-developer/* as an app presentational
  extract (test case mirrored)
- gallery-index: surfaces-rail-apps shell entry + overview row
- surfaces.tsx: render the fixture in SurfacesShellPage under
  data-testid=surfaces-rail-apps (no new route)
Move the /capabilities markup into
components/developer/presentational/capabilities-page-chrome.tsx (copy as
props, no transport/router/i18n) and relocate the page to
components/developer/capabilities-page.tsx as pure wiring, so the Design
Studio fixture renders it from static view models.

Split the collapsed empty state into two branches: registry-empty (unchanged
copy, wins over a filter) and filtered-miss (new keys quoting the query plus
a Clear filter action via the EmptyState action slot). Match semantics and
the read-only ?filter= seed are unchanged.

Register the four-variant fixture (empty registry, filtered hit, filtered
miss, error) in the Studio surfaces shell gallery, both themes.
Replace the sessions table with the v1.220 hub card frame: the short session
id as the card title, the unchanged `statusVariant` pill, then Preset /
Creator — `current_task_id` is dropped from the surface (the run view owns the
in-flight pointer; the contract field and query stay untouched). The whole
card is one link to `/sessions/<encodeURIComponent(session_id)>`, so each card
is a single focus stop and `HubCard`'s `go` slot stays unused (no nested link).

The card markup lands in
`components/developer/presentational/session-card.tsx` (resolved view models
plus an injected `renderLink`, no router/i18n) and the page relocates to
`components/developer/sessions-page.tsx` as pure wiring; both the creator and
developer `session` AppDefs repoint to it.

`HubCard.title` widens to `ReactNode` and its status variant to
`BadgeProps['variant']` — type-only, the Hub cards keep passing strings.

The zero-session copy becomes "No sessions yet" / "Sessions appear here when a
preset run starts." (the list also holds terminal sessions). Register the mixed
running/completed/failed grid plus the empty state in the Studio surfaces shell
gallery, both themes.
The chrome hardcoded id="caps-filter" for its label/input pair, so the four
gallery mounts produced four duplicate DOM ids and each label focused the
first input in the document. Generate the id with useId() so every mount is
self-consistent and unique.

Also drop data-testid="capabilities-page-body", which had no consumer.

The design-studio fixture test now asserts the four frames get pairwise
distinct ids, each id appears once in the document, and getByLabelText
resolves each frame's own filter input.

Refs QC3-R-1, QC3-R-2.
@greptile-apps

greptile-apps Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; the earlier duplicate-ID finding is fully addressed.

Summary

Rebuilds the Modules, Capabilities, and Sessions developer pages with shared display components and Design Studio fixtures.

  • The Modules rail page now owns the shared Run Studio.
  • The Capabilities page separates an empty registry from a filter miss.
  • The Sessions page shows linked cards instead of a table.
  • Design Studio now shows the three developer rail pages in static fixtures.
  • Web test and host helpers keep their existing behavior.

Reviews (4) · Last reviewed commit: "Merge branch 'fix/pr445-review-r3' into ..." · Reviewed by Greptile

Comment thread apps/web/src/components/developer/presentational/run-studio-chrome.tsx Outdated
CI web vitest failed with "TypeError: document.getElementById(...)
?.scrollIntoView is not a function" from the Settings anchor scroll
effect in settings-modal-host.tsx: jsdom does not implement
Element.prototype.scrollIntoView, and the uncaught requestAnimationFrame
callback error failed the run even with 222 files / 2349 tests passing.

Optional-call the method; behavior in real browsers is unchanged.
greptile-apps[bot]
greptile-apps Bot previously approved these changes Oct 24, 2026

@auto-wood auto-wood left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Verdict: needs fixes · Score 66% (pass)

Findings Count
🔴 must-fix 0
🟠 should-fix 3
🔵 nit 6
❓ unverified 0

📋 Review

What this PR does: Completes the developer rail registry (操作台 / Harness / 模块 / 能力 / 会话) under the 2026-10-22 web-rebuild authorization: /modules becomes a first-class rail app with Settings-modal ownership deleted outright, capabilities and sessions rails lifted to the same generation (chrome/view split, hub-card sessions, deep links preserved), design-studio fixture + gallery wiring, an I-000058 trailing-space fold tripwire, and the thrice-verified rail-app rebuild recipe promoted to knowledge.

Revalidated findings

none

Findings

🟠 Legacy /settings/modules deep links silently land on the Agent settings section (I-000085)

  • Evidence: apps/web/src/components/layout/settings-section-registry.ts:125-145 — after the ownership deletion, /settings/modules matches no special case and falls back to DEFAULT_SETTINGS_SECTION (agent); settings-modal-context.tsx:116-136 preserves location.search, so the URL becomes /settings/agent?module=…&run=….
  • Impact: v1.147 shipped in-app navigation to /settings/modules (git 99d58f4fe, canvas-nav-commands.tsx:162, tests pinned /settings/modules?world=…), so old bookmarks/tabs render the wrong section with no signal. The closeout knowledge entry's "the product has never shipped" premise is contradicted by git history — the no-redirect decision stands on a false fact.
  • Merge class: should-fix
  • Confidence: HIGH
  • Fix sketch: explicit alias /settings/modules → /modules preserving search, or correct the knowledge decision record with explicit product sign-off on dropping those URLs.

🟠 Run Studio chrome ×3 in modules gallery with duplicate static DOM ids (I-000086)

  • Evidence: run-studio-chrome.tsx:199-348 hardcodes run-studio-world / run-runs-status-filter / run-runs-world-filter; modules-rail-fixtures.tsx:464-497 mounts RunStudioChrome three times in one document. This PR itself converted the capabilities chrome to useId() (capabilities-page-chrome.tsx:88, commit 8bde104) with a negative-checked fixture test — the modules side lacks both, against knowledge recipe item 6.
  • Impact: label→control association and AT navigation break in the Studio acceptance surface; the documented regression defence (reverting to hardcoded ids must turn the suite red) does not exist here.
  • Merge class: should-fix
  • Confidence: HIGH
  • Fix sketch: useId() in RunStudioChrome + pairwise-distinct id assertion mirroring capabilities-rail-fixtures.test.tsx:36-48.

🟠 "Both themes" fixture passes assert fixture-owned classes — the dark pass proves nothing (I-000087)

  • Evidence: capabilities-rail-fixtures.test.tsx:110-111 and modules-rail-fixtures.test.tsx:95-96 assert classes authored in the fixtures' own markup; vitest.config.ts:65 runs css: false, so the dark toggle has no observable effect.
  • Impact: the PR's "both themes" coverage cannot fail even if a chrome hardcoded a light-only color. The sessions fixture does it right by asserting product HubCard token-backed classes.
  • Merge class: should-fix
  • Confidence: HIGH
  • Fix sketch: assert a chrome-owned token class, or drop the assertion and declare theme parity visual-gallery-only.

🔵 Locale: zh-CN settings nav workspace stays English ("Profiles")

  • Evidence: apps/web/src/locales/zh-CN/settings.json:9 — the diff edits this exact block (removes nav.modules) and leaves the parity defect.
  • Merge class: nit · Confidence: HIGH
  • Fix sketch: zh-CN nav.workspace: "配置档案" (or comment the intentional product term).

🔵 Registry tests assert source shape, not product behavior

  • Evidence: settings-section-registry.test.ts:15-27 pins SETTINGS_SECTION_IDS order and labelKey === nav.${id}; entrance-registry.test.ts pins rule-array contents/icon wiring.
  • Merge class: nit · Confidence: MEDIUM
  • Fix sketch: keep one nav-order contract test (user-visible order); delete the labelKey/icon shape pins or replace with rendered-nav-label assertions.

🔵 Surfaces index footer prose not updated for the new rail sections

  • Evidence: apps/design-studio/src/pages/surfaces.tsx:512-563 — the surface/source enumerations stop at Selection Submenu while lines 802-858 add three new sections and the @web-developer/* extract root.
  • Merge class: nit · Confidence: HIGH
  • Fix sketch: add the three rails and @web-developer/* to both lists.

🔵 Non-product test assertions: badge class/innerHTML pins, unbound getByText('3')

  • Evidence: sessions-rail-fixtures.test.tsx:71-73 and hub-card.test.tsx:55 pin @42ch/nexus-ui class names (innerHTML); modules-rail-fixtures.test.tsx:53-54 asserts an unbound getByText('3') any "3" satisfies. Badge-class pins follow an existing repo convention (sessions-page.test.tsx:121-127).
  • Merge class: nit · Confidence: HIGH
  • Fix sketch: delete the innerHTML pin (or replace with a status→variant product assertion); scope the ABI value to its field row.

🔵 Stale invalidation comment in the canvas compute journey

  • Evidence: compute-events-canvas.test.tsx:169 documents a timeline.all invalidation the journey no longer exercises (unmount at :391-393, remount+refetch at :476-478).
  • Merge class: nit · Confidence: HIGH
  • Fix sketch: update the comment to the remount mechanism.

🔵 session-card.tsx relative import exits the presentational/ alias root

  • Evidence: session-card.tsx imports ../hub-card while the chrome convention (knowledge recipe item 2) allows hub-card only as an explicit composition exception via alias.
  • Merge class: nit · Confidence: HIGH
  • Fix sketch: use the @/components/developer/hub-card path.

Linked-issue AC

  • I-000058 (trailing-space fold tripwire): met — /v1%20/y added to the HTTP fold matrix and v1 /x to the unit-seam refusal array.
  • I-000084 (Advanced-JSON open-state assertion): cut — disclosed residual, tracked open as I-000084 by the PR itself.

✅ Verified

  • Full diff basis read (7774-line pinned pack, origin/main...pr-445).
  • Deep links preserved on the new surface: modules-page.tsx:69-81, capabilities-page.tsx:36, query write-back in selectModule/onRunOpen.
  • Dead-code sweep: no remaining importers of deleted pages/*-page, settings-modules-section, nav.modules, Cpu, SettingsModalContext.
  • Locale parity en vs zh-CN across rail namespaces — clean.
  • Security lenses (XSS, hrefs, deep-link params, entrance guards, static-serve, supply-chain) — no reachable sink with attacker-controlled input.
  • ❓ CI (PR's own unchecked checkbox) — not verifiable at review time; a pre-existing red build is not a diff finding.

🗑️ Considered & rejected

  • XSS via rendered fixture/registry content: rejected — React text/i18n interpolation only, no HTML sink.
  • Session whole-card link open-redirect/javascript: scheme: rejected — encodeURIComponent + react-router <Link>.
  • Entrance guard weakening from the settings deletion: rejected — /modules keeps the develop-only rule; no route newly reachable.
  • Static-serve regression: rejected — product change is comment-only; the test change tightens the /v1 fold refusal (I-000058 tripwire).
  • "No redirect" as full by-design defence for the alias finding: rejected as a complete defence — the decision is recorded in knowledge, but its factual premise (never shipped) is falsified by v1.147 history.

🛠️ Plan to fix

Expand fix plan
1. SF-2 (I-000086): `useId()` in `run-studio-chrome.tsx` for the three control ids; add pairwise-distinct id assertion + negative check to `modules-rail-fixtures.test.tsx`.
2. SF-1 (I-000085): decide alias vs record-correction. Either add `/settings/modules → /modules` alias preserving search, or fix `.mstar/knowledge/architecture-patterns/developer-rail-app-rebuild.md` item 1's "never shipped" premise with explicit product sign-off.
3. SF-3 (I-000087): re-point both theme-loop class assertions at chrome-owned token-backed classes (sessions style), or drop them and declare theme parity visual-gallery-only.
4. Nits batch: zh-CN `nav.workspace` label; surfaces.tsx footer enumerations; delete `hub-card.test.tsx` innerHTML pin + scope ABI `'3'`; update `compute-events-canvas.test.tsx:169` comment; `session-card.tsx` alias import.
5. Verification: `pnpm --filter web typecheck && pnpm --filter design-studio typecheck`; targeted vitest (modules/caps/sessions fixtures, hub-card, registry, entrance, static-serve).

session-card.tsx reached ../hub-card, a relative import that exits the
@web-developer presentational root (and resolves only through Studio's
web-src fallback). HubCard is a read-only frame with no product wiring,
so move it into presentational/ and import it as a sibling; update the
two product importers to the new path.

Review nit (cross-domain security seat handoff).
…tions

I-000086 / Greptile 4367153745: the modules gallery mounts RunStudioChrome
three times; hardcoded run-studio-world / run-runs-status-filter /
run-runs-world-filter ids collided, so every label after the first frame
pointed at frame 1's control. Derive them with useId() (same pattern as
the capabilities chrome fix) and pin the contract in the fixture test:
pairwise-distinct ids per control, each id unique in the document, each
label resolving inside its own frame. Negative-checked by reverting the
status filter id to a literal — the test goes red.

I-000087: the 'both themes' tests asserted fixture-owned classes with
css:false, which can never fail. Render each fixture under the Studio
ThemeProvider's forcedTheme and assert the theme marker (<html>.dark)
flips with it, plus the frames still render.

Refs I-000086, I-000087.
…footer

- zh-CN settings nav.workspace was left as the English 'Profiles'; use the
  repo's 个人档案 terminology.
- compute-events-canvas: the journey returns to the Timeline by route, so
  the canvas remounts and refetches; the comment claimed timeline.all
  invalidation, which this path no longer exercises.
- Surfaces index lists the three new rail-app fixtures and @web-developer/*
  in its source enumeration.
PR #445 SF-1 asked for the no-alias decision to be signed off explicitly
rather than resting on an unrecorded premise. Record product decision
D4 (2026-10-24): /settings/modules falls back to the default settings
section, no redirect; the route only ever existed in in-app navigation in
pre-release builds, and the disposition expires if the product ever ships
with it reachable. Also corrects the recipe's hub-card import path after
the presentational move.

Refs I-000085.
greptile-apps[bot]
greptile-apps Bot previously approved these changes Oct 24, 2026

@auto-wood auto-wood left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Verdict: needs fixes · Score 82% (good)

Findings Count
🔴 must-fix 0
🟠 should-fix 1
🔵 nit 5
❓ unverified 0

📋 Review

What this PR does (round-2 increment 1959c45..1aaf7af, 12 files +88/−32): lands the round-1 fix wave — useId() for the Run Studio selects + negative-checked fixture assertion (SF-2), theme loops driven by ThemeProvider forcedTheme (SF-3), a D4 PM sign-off note in the knowledge recipe for the legacy /settings/modules disposition (SF-1), zh label, surfaces footer, stale comment, the hub-card move into presentational/, and a pre-round-2 jsdom scrollIntoView CI fix.

Revalidated findings

Prior finding State Evidence
SF-1 /settings/modules alias (I-000085) fixed knowledge disposition section — D4 decision, PM sign-off 2026-10-24, corrected premise, expiry clause requiring a real alias if the product ever ships
SF-2 duplicate static ids (I-000086) fixed run-studio-chrome.tsx:188-190 three useId(); negative-checked test modules-rail-fixtures.test.tsx:37-58
SF-3 fixture-owned theme assertions (I-000087) fixed forcedTheme is the real theme authority (theme-provider.tsx:45-56, effect :72-79); fixture-owned class assertions deleted
N-1 zh nav.workspace English fixed zh-CN/settings.json:9 "个人档案"
N-3 surfaces footer stale fixed surfaces.tsx:203-208, :552-557, :524-526
N-4 badge class/innerHTML pins + unanchored '3' still present hub-card.test.tsx:55; modules-rail-fixtures.test.tsx:79 (disclosed)
N-5 stale invalidation comment fixed compute-events-canvas.test.tsx:168-171
N-6 session-card relative import fixed R100 rename; session-card.tsx:17 ./hub-card; zero stale importers
N-2 registry source-shape assertions still present disclosed

Findings

🟠 RunFormFields idPrefix="run-form" literal still duplicates ids across the 3-frame gallery (I-000086, occurrence 97)

  • Evidence: run-studio-chrome.tsx:246 passes the literal; packages/nexus-ui/src/components/run-form-fields.tsx:148 builds `${idPrefix}-${name}` with htmlFor binding; all three fixture frames pass a proposal and render RunFormFields (modules-rail-fixtures.tsx:455-500).
  • Impact: run-form-attacker_id / run-form-defender_id (+ -helper) appear 3×, so labels in frames 2/3 resolve to frame 1's controls — the same invariant SF-2 fixed for the selects, on the same acceptance surface. The new chrome comment (:186-187) overstates the fix's scope.
  • Merge class: should-fix
  • Confidence: HIGH
  • Fix sketch: const formIdPrefix = useId(); → idPrefix={formIdPrefix}; extend the fixture label list with the form-field labels so the negative check covers them.

🔵 Theme-test comments overstate what the assertion proves

  • Evidence: capabilities-rail-fixtures.test.tsx:110-112, modules-rail-fixtures.test.tsx:119-121 — with css: false the html.dark marker assertion proves the provider resolved the theme, not that the fixture adapts; visual parity stays gallery-only.
  • Merge class: nit · Confidence: HIGH
  • Fix sketch: reword to "asserts the Studio theme authority drives the html.dark marker; visual parity stays gallery-only".

🔵 Rail apps enumeration omits the capabilities read-error variant

  • Evidence: surfaces.tsx:524-525 says "Capabilities (registry, filter, empty)" while the section body renders a read-error state (:846-853).
  • Merge class: nit · Confidence: HIGH
  • Fix sketch: add "error" to the enumeration.

🔵 hub-card.test.tsx left one directory away from its moved subject

  • Evidence: component is now presentational/hub-card.tsx; the test stayed at components/developer/hub-card.test.tsx (import updated only).
  • Merge class: nit · Confidence: MEDIUM
  • Fix sketch: move alongside presentational/ when the disclosed innerHTML pin is rewritten.

🔵 Disclosed not fixed (carried): registry source-shape assertions + badge class/innerHTML pins

  • Evidence: settings-section-registry.test.ts:15-27; hub-card.test.tsx:55 innerHTML pin; modules-rail-fixtures.test.tsx:79 frame-scoped getByText('3').
  • Merge class: nit · Confidence: HIGH
  • Fix sketch: as agreed — product-behaviour rewrites or deletion.

Linked-issue AC

  • I-000058 (trailing-space fold tripwire): met — unchanged; the increment does not touch the serve tests.
  • I-000084 (Advanced-JSON open-state assertion): cut — still tracked open by the PR.

✅ Verified

  • merge-base --is-ancestor 1959c450 1aaf7af58 — covering prior report, increment-only scope (325-line pack read in full).
  • forcedTheme prop and the html.dark effect confirmed in theme-provider.tsx — the new theme assertion has a real authority behind it.
  • idPrefix duplication traced end-to-end: literal at run-studio-chrome.tsx:246 → id generation run-form-fields.tsx:148 → all three gallery frames render the form.
  • Zero stale @/components/developer/hub-card importers (repo grep).
  • ❓ Negative-check runtime red/green not executed (read-only review; author reports it ran pre-push).

🗑️ Considered & rejected

  • SF-1 "no alias" as unresolved: rejected — the D4 sign-off corrects the false premise, records the decision in the knowledge ADR-equivalent, and carries an expiry clause; valid disposition for a risk that requires the product to ship.
  • NEW-1 as SF-2 "regressed": rejected — the select-side fix stands; the form-field residue is one new should-fix finding, captured as an occurrence on I-000086, not double-counted.
  • hub-card Link import as should-fix: rejected — knowledge item 2 now names the ./hub-card sibling exception; the whole-card link is product behaviour. (Adjudication note: the cited precedent shell-sidebar-chrome.tsx does not exist; the presentational-layer precedent daemon-health-indicator-chrome.tsx:20 uses renderer injection — the knowledge wording could name the Link exception explicitly.)

🛠️ Plan to fix

Expand fix plan
1. SF-R2 (I-000086): `useId()` for the RunFormFields idPrefix in `run-studio-chrome.tsx`; add the Attacker/Defender labels to the modules fixture id-uniqueness test so a literal idPrefix turns it red. Adjust the :186-187 comment scope.
2. Nit batch: reword both theme-test comments; add "error" to the surfaces Rail apps enumeration; move `hub-card.test.tsx` beside its subject with the product-behaviour rewrite of the innerHTML pin.
3. Verification: targeted vitest (modules-rail-fixtures, hub-card, registry) + `pnpm --filter web typecheck && pnpm --filter design-studio typecheck`.

run-studio-chrome passed the literal idPrefix="run-form" into
RunFormFields, so the gallery's three Run Studio frames emitted the same
run-form-<field> ids and frames 2/3' labels resolved to frame 1's
control. Derive the prefix from useId() like the sibling select ids, and
extend the modules-rail fixture test to cover the schema field labels.

@auto-wood auto-wood left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Verdict: ship it · Score 94% (mergeable)

Findings Count
🔴 must-fix 0
🟠 should-fix 0
🔵 nit 5
❓ unverified 0

📋 Review

What this PR does (round-3 increment 1aaf7af..f55af51, 2 files +12/−2): closes the round-2 blocking item — RunStudioChrome derives the Run form's id prefix via useId() and passes idPrefix={formIdPrefix}, and the modules gallery duplicate-id test extends its negative check to the schema field labels (Attacker/Defender).

Revalidated findings

Prior finding State Evidence
SF-R2 RunFormFields literal idPrefix (I-000086 occ 97) fixed run-studio-chrome.tsx:191,247; fixture labels modules-rail-fixtures.test.tsx:52-53; dual red paths on revert (Set-size=1; [id=] ×3)
Theme-test comment overstatement (NEW-2) still present capabilities-rail-fixtures.test.tsx:110-112, modules-rail-fixtures.test.tsx:119-121
Rail apps enumeration omits error variant (NEW-3) still present surfaces.tsx:524-525
hub-card.test.tsx one directory from subject still present untouched
N-2 / N-4 disclosed carried nits still present disclosed

The chrome comment (run-studio-chrome.tsx:186-191) is now accurate for the whole chrome — all four id bindings are useId()-scoped.

Findings

none new. The five carried nits remain listed above (deduct 6 points, cap 8) — none is merge-blocking; a cleanup pass can take them together.

Linked-issue AC

  • I-000058 (trailing-space fold tripwire): met — unchanged.
  • I-000084 (Advanced-JSON open-state assertion): cut — still tracked open by the PR.

✅ Verified

  • merge-base --is-ancestor 1aaf7af58 f55af51f6 — covering increment scope (2-file pack read in full by main agent + quick seat).
  • Id chain end-to-end: useId() prefix → run-form-fields.tsx:148 → htmlFor/id pairs (entity-picker-field.tsx:71,88); chrome subtree has zero remaining static ids; repo-wide grep: zero consumers of the old literal.
  • Negative check judged genuinely red on revert via two independent assertions; :rN: ids safe under the quoted selector.
  • ❓ Runtime red/green not executed (read-only review; author/CI report it ran).

🗑️ Considered & rejected

  • Carried nits as verdict-relevant: rejected — nits alone cannot change the tally-derived verdict; they stay listed for the cleanup pass.

🛠️ Plan to fix

Expand fix plan
None required for merge. Optional cleanup pass (non-blocking):
1. Reword the two theme-test comments (provider marker vs visual parity).
2. Add "error" to the surfaces Rail apps enumeration.
3. Move hub-card.test.tsx beside its subject with the product-behaviour rewrite of the innerHTML pin; delete/replace the registry source-shape pins and the frame-scoped getByText('3').

@auto-wood
auto-wood merged commit 2bbad18 into main Oct 24, 2026
30 checks passed
@auto-wood
auto-wood deleted the iteration/v1.221-developer-rails branch October 24, 2026 13:41
auto-wood added a commit that referenced this pull request Oct 24, 2026
… residue

Five carried PR #445 R3 nits, each with a recorded disposition:
- theme comments (capabilities + modules rail fixtures) reduced to the one
  claim they prove: ThemeProvider applied the resolved `<html>.dark` marker.
- rail-apps prose in the Studio surfaces page now enumerates the fixtures'
  own VARIANTS (Modules six states incl. the Advanced-JSON open frame,
  Capabilities four, Sessions two).
- hub-card.test.tsx moved beside its subject and imports `./hub-card`.
- registry source-shape pins trimmed to one order contract per list;
  the descriptor mirrors and naming loops are gone.
- hub-card innerHTML string pin deleted (Badge owns that mapping); the ABI
  value assertion is scoped to its own DetailField row instead of the frame.

Comment residue: the compute inspector points at `/modules?module=&run=`
instead of "Settings → Modules", and the timeline invalidation note drops
the canvas-behind-the-Settings-modal clause. The four re-sync comments and
the sessions badge class pins stay by decision.
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