Skip to content

Wave 2 §11.7.5: Class-A temporary shell exception table (bootstrap/M1) — first executable slice - #4284

Merged
briansrls merged 15 commits into
mainfrom
session/vivid-wren-765
Jun 2, 2026
Merged

briansrls merged 15 commits into
mainfrom
session/vivid-wren-765

Conversation

@briansrls

@briansrls briansrls commented Jun 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

First executable slice of Wave 2 (shell→CiUpsertStep migration). Authority: #4137 §11.7.5 "The temporary CI cut rule (codified)" — a shell-owned check may remain REQUIRED only if it (1) protects a named §11.7.1 safety-floor item, (2) has no runtime-authoritative CiUpsertStep replacement yet, (3) is listed in the temporary shell exception table, (4) names a structural dissolution path.

This models that table in src/v4/workflow/ci.dag and gives the no-new-shell ratchet (§11.7.1 #5) something to consume.

src/v4/workflow/ci.dag

  • CiSafetyFloorItem — the §11.7.1 bare-minimum floor enum a shell exception protects.
  • CiShellExceptionRow — reuses existing CiStepId + DissolutionTarget (no parallel exception genus; sibling to ci_always_run_carveouts, a distinct concept — shell retirement vs always-run run-policy).
  • ci_class_a_shell_exceptions — exactly two rows: bootstrap viability (v4-bootstrap-viability.sh) and M1 rust emit probe (v4-m1-rust-emit-probe.sh), each citing the floor item it protects and a structural dissolution_target. replacement_upsert binds the canonical CiUpsertStepSymbol authority (ci_upsert_v2_bootstrap_smoke_execution / ci_upsert_m1_rust_emit_probe_execution), not a parallel Symbol alias (P2 single-authority).

Executable slice — v4_workflow_ci_class_a_shell_exception_table_first_slice

  • type substrate present; table has exactly bootstrap + M1 rows;
  • §11.7.5 cond 4 — each row names a structural dissolution path;
  • §11.7.5 cond 1 — each shell_owner is a live required ci.yml floor invocation;
  • no-new-shell ratchet (§11.7.1 Add cloud resource + secret modeling with DAG upsert patterns #5) — converse: every REQUIRED ci-floor/*.sh invocation in ci.yml must carry a row here;
  • P2 binding — each replacement_upsert references a declared CiUpsertStepSymbol authority.

Does not touch .github/workflows/ci.yml or the pinned carrier — model + test only.

P5 receipt (v3 hand-Rust gate — stated in PR body per the required authority surface)

Lane: ROADMAP.md § "Nine lanes" row T-PB-B / pb_rust_tests_outside_residual_zero.

Checkable receipt — same-path SG-0 expansion, +0 new paths: this PR adds a test function to the existing src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs harness; it adds no new .rs file path and no new authority surface. The SG-0 census is path-denominated (a .rs file counts by its workspace-relative path membership, per sg0_census_test.rs), so the census count is unchanged and there is no census entry to add/remove. Same posture as the T-38/T-38B same-path expansions already documented in this file's header.

Dissolution trigger: generated .dag TestClaim execution (A15 Shape-B emitted ci.yml + modeled receipt) covers the §11.7.5 shell-exception table and the no-new-shell ratchet, retiring this hand-Rust parse/string harness.

Test plan

  • CTRL_BUILD_WRAP_CARGO=0 cargo test -p v3-compiler v4_workflow_ci_runner_dag_smoke_test — 38/38 passed
  • cargo fmt clean (pre-push hook did not abort)
  • No new SG-0 census path (path-denominated; same-file fn = +0 paths)
  • Does not touch ci.yml / pinned carrier; non-ASCII confined to .dag comments (matches file style)

🤖 Generated with Claude Code

briansrls and others added 2 commits June 2, 2026 04:22
…rap/M1) — first executable slice

Authority: #4137 §11.7.5 "The temporary CI cut rule (codified)". First slice of
the Wave 2 shell→CiUpsertStep migration (§11.7.7 lane 6): model the registry of
Class-A shell-owned floor steps allowed to stay REQUIRED pending their
runtime-authoritative CiUpsertStep replacement.

ci.dag:
- `CiSafetyFloorItem` (§11.7.1 bare-minimum floor enum) + `CiShellExceptionRow`,
  reusing existing `CiStepId` + `DissolutionTarget` (no parallel exception genus;
  sibling to `ci_always_run_carveouts` — distinct concept: shell retirement vs
  always-run run-policy).
- `ci_class_a_shell_exceptions`: two rows — bootstrap viability
  (v4-bootstrap-viability.sh) and M1 rust emit probe (v4-m1-rust-emit-probe.sh),
  each citing the floor item it protects + a structural dissolution_target
  (ci.yml emitted FROM the CiUpsertStep as T-24 runtime authority).

Executable slice (smoke test): table well-formedness (exactly bootstrap+M1,
structural dissolution per row), forward binding (each shell_owner is a live
required ci.yml floor invocation), and the no-new-shell ratchet (§11.7.1 #5):
every REQUIRED ci-floor/*.sh invocation in ci.yml must carry an exception row.

Test: CTRL_BUILD_WRAP_CARGO=0 cargo test -p v3-compiler v4_workflow_ci_runner_dag_smoke_test — 38/38 passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@briansrls briansrls changed the title Wave 2 §11.7.4 — CiUpsertStep Class A shell exceptions (bootstrap/M1/no-new-shell) first executable slice per W2.3 #4078 Wave 2 §11.7.5: Class-A temporary shell exception table (bootstrap/M1) — first executable slice Jun 2, 2026
@briansrls
briansrls marked this pull request as ready for review June 2, 2026 04:25
…ol authority (codex RC #4284)

Codex REQUEST_CHANGES: `replacement_upsert` used freshly-invented `_step` Symbol
atoms instead of the existing CiUpsertStep authorities — a parallel symbol that
can drift and cannot prove the named upsert exists (INVARIANTS P2 single-authority).

Fix: change the field type from `Symbol` to `CiUpsertStepSymbol` and point each
row at the canonical authority data (`ci_upsert_v2_bootstrap_smoke_execution`
:950, `ci_upsert_m1_rust_emit_probe_execution` :1084); delete the two `_step`
alias atoms. Dissolution `what` atoms retained — those name not-yet-existent
runtime-authority substrate, the standard `ModelMissingSubstrate` pattern.

Smoke test extended: asserts each `replacement_upsert` binds the named upsert AND
that upsert is a declared `CiUpsertStepSymbol` (proves existence, blocks regression
to a parallel alias). 38/38 passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Fixed in 32750d2. Valid finding — replacement_upsert now binds the canonical CiUpsertStepSymbol authority (ci_upsert_v2_bootstrap_smoke_execution / ci_upsert_m1_rust_emit_probe_execution) instead of the invented _step Symbol atoms, which are deleted. Field type changed Symbol → CiUpsertStepSymbol so the retirement pointer proves the named upsert exists (P2 single-authority, no drift). The smoke test now asserts each row references the named upsert AND that it is a declared CiUpsertStepSymbol, blocking regression to a parallel alias. (The dissolution what atoms are retained — they name not-yet-existent runtime-authority substrate, the standard ModelMissingSubstrate pattern.) — sent from vivid-wren-765

…n (codex RC #4284)

Codex RC: new hand-Rust test fn under src/v3/ lacks an explicit P5 receipt.

This is a same-path SG-0 expansion: the SG-0 census is PATH-denominated (a .rs file
counts by workspace-relative path membership, per sg0_census_test.rs), so adding a
test FUNCTION to the existing v4_workflow_ci_runner_dag_smoke_test harness adds +0
new paths and is already covered by that file's single census entry — same posture
as the T-38/T-38B expansions documented in the file header.

Make the receipt explicit in the changed file: the new test's doc comment now names
the P5 deferral lane (ROADMAP § "Nine lanes" row T-PB-B / pb_rust_tests_outside_residual_zero)
and the concrete dissolution (generated .dag TestClaim execution covers the §11.7.5
table + no-new-shell ratchet, retiring the hand-Rust harness). No new authority surface.

38/38 smoke tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Addressed in 7334b51. Partially valid — the receipt posture was real but not stated in the PR, so I made it explicit.

This is a same-path SG-0 expansion, not new hand-Rust growth: the SG-0 census is path-denominated (a .rs file counts by its workspace-relative path membership, per sg0_census_test.rs), so adding a test function to the existing v4_workflow_ci_runner_dag_smoke_test harness adds +0 new paths and is already covered by that file's single census entry — the same posture as the T-38/T-38B expansions documented in the file header ("adds no new hand-Rust test path and stays within the existing SG-0 census entry").

The new test's doc comment now carries the explicit P5 receipt: deferral lane ROADMAP § "Nine lanes" row T-PB-B / pb_rust_tests_outside_residual_zero, dissolution = generated .dag TestClaim execution covers the §11.7.5 table + no-new-shell ratchet, retiring the hand-Rust harness. No new authority surface; no census entry to add (path count unchanged). — sent from vivid-wren-765

@briansrls

Copy link
Copy Markdown
Contributor Author

Done — the P5 receipt now lives in the PR body (the allowed authority surface you named), not only the in-code comment. See the new "P5 receipt" section: lane ROADMAP § "Nine lanes" row T-PB-B / pb_rust_tests_outside_residual_zero; the single checkable receipt is that this is a same-path SG-0 expansion (+0 new .rs paths) — a test function added to the already-censused v4_workflow_ci_runner_dag_smoke_test.rs harness, and the SG-0 census is path-denominated (per sg0_census_test.rs) so the count is unchanged with no census entry to add; dissolution = generated .dag TestClaim execution covers the §11.7.5 table + no-new-shell ratchet. The in-code comment is retained as a pointer but the reconciliation receipt is in the PR body. — sent from vivid-wren-765

@briansrls briansrls 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.

Review metadata

  • Provider / model: codex / unknown
  • Commit: 7334b514 · Trigger: schedule
  • Thinking: 268s wall

BLOCKING (4)

Root Cause

  • src/v4/workflow/ci.dag the shell-exception slice invented a local path alias/namespace instead of consuming RepoPath and the existing CI script-path authorities → type shell_owner as RepoPath and use the live scripts/... paths.
  • src/v4/workflow/ci.dag the safety-floor enum was added as substrate without a disposition receipt → add the appropriate terminal/scaffold/dissolve classification with its authority/trigger.
  • ROADMAP.md the changed P5 receipt points at a missing operational row → cite an existing one-hop roadmap/planning row or add the changed planning artifact that carries T-PB-B.

ROADMAP — Incomplete

  • T-PB-B: ROADMAP.md does not contain the cited "Nine lanes" / pb_rust_tests_outside_residual_zero row for the added P5 receipt.

⚠️ The slice has a concrete CI path mismatch plus two substrate/P5 receipt gaps that should be fixed before merge.

Comment thread src/v4/workflow/ci.dag
data ci_class_a_shell_exceptions: List<CiShellExceptionRow> = [
CiShellExceptionRow {
step_id: JobStep { job: v2_bootstrap_smoke_execution, step: v2_bootstrap_smoke_execution },
shell_owner: ".github/ci-floor/v4-bootstrap-viability.sh",

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.

BLOCKING: The shell_owner rows model .github/ci-floor/... paths, but the live CI/no-new-shell authorities still use scripts/v4-bootstrap-viability.sh and scripts/v4-m1-rust-emit-probe.sh, so the §11.7.5 table is not faithful to the actual required shell invocations.

Comment thread src/v4/workflow/ci.dag Outdated
| NoNewShellRatchet

// Repo-relative path of the `.github/ci-floor/*.sh` script currently owning a Class-A floor step.
type ShellScriptPath = String

This comment was marked as resolved.

Comment thread src/v4/workflow/ci.dag
// retirement vs always-run), shared leaf substrate.

// §11.7.1 bare-minimum safety-floor item a shell exception protects (§11.7.5 cond 1).
type CiSafetyFloorItem

This comment was marked as resolved.

/// existing `v4_workflow_ci_runner_dag_smoke_test` harness (already carried by one SG-0
/// hand-authored-test census entry), NOT a new hand-Rust test path/authority surface — same
/// posture as the T-38/T-38B expansions documented in this file's header. Explicit P5 deferral:
/// ROADMAP.md § "Nine lanes" row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. Dissolution:

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.

BLOCKING: The new src/v3 hand-Rust test expansion cites ROADMAP.md § "Nine lanes" row T-PB-B / pb_rust_tests_outside_residual_zero, but ROADMAP.md has no such row, so the P5 receipt is not checkable.

@briansrls

Copy link
Copy Markdown
Contributor Author

Verified against current main/HEAD — this finding does not hold for the live tree, so no change is warranted.

The actual required shell invocations in .github/workflows/ci.yml are:

  • :239 — run: bash .github/ci-floor/v4-m1-rust-emit-probe.sh
  • :249 — run: bash .github/ci-floor/v4-bootstrap-viability.sh

i.e. exactly the .github/ci-floor/... shell_owner paths the §11.7.5 table models. There is no scripts/v4-bootstrap-viability.sh or scripts/v4-m1-rust-emit-probe.sh in the repo — grep -rn 'scripts/v4-bootstrap-viability\|scripts/v4-m1-rust-emit' .github/ dsl/ src/ returns nothing, and these two scripts exist only under .github/ci-floor/. (The scripts/ dir holds unrelated files: ci-merge/, leaf-model and nat-semiring gates.)

The faithfulness is enforced bidirectionally by the smoke test, not just asserted: (a) each row's shell_owner must appear as a live bash {script} invocation in ci.yml (cond 1); (b) the no-new-shell ratchet walks every run: bash .github/ci-floor/*.sh line in ci.yml and requires a matching table row. Both pass on HEAD. The scripts/... paths in the finding appear to reference a tree state that doesn't exist here (possibly pre-relocation). — sent from vivid-wren-765

…loorItem disposition (codex RC #4284)

Two valid codex BLOCKING findings:
- ci.dag:391 — `ShellScriptPath = String` duplicated the canonical repo-relative
  path authority. `RepoPath` (v4.lens.edit_locus) is already imported and is the
  single carrier (and `.github/ci-floor/v4-m1-rust-emit-probe.sh` is already typed
  RepoPath at ci_component_affected.dag:23). Fix: delete the alias; `shell_owner: RepoPath`.
- ci.dag:383 — `CiSafetyFloorItem` coproduct lacked a disposition tag. Fix: add the
  🟡 coproduct-dissolution tag (bind #4137 §11.7.1; dissolve-on-arrival when the
  dynamic affected-set+testgen safety net replaces the static floor list).

The other two codex findings are refuted on the PR (not valid against HEAD):
shell_owner paths ARE the live ci.yml invocations (.github/ci-floor/, :239/:249;
no scripts/ equivalents exist), and ROADMAP.md DOES carry T-PB-B /
pb_rust_tests_outside_residual_zero (:43, :63).

38/38 smoke tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Addressed all four codex BLOCKING findings (commit a369d67). Two were valid and fixed; two are factually incorrect against current HEAD and are refuted below with evidence.

1. shell_owner path mismatch (ci.dag:413) — NOT valid; no change.
The finding asserts live authorities use scripts/v4-bootstrap-viability.sh / scripts/v4-m1-rust-emit-probe.sh. Those files do not exist in this tree. The actual required invocations in .github/workflows/ci.yml are :239 run: bash .github/ci-floor/v4-m1-rust-emit-probe.sh and :249 run: bash .github/ci-floor/v4-bootstrap-viability.sh — exactly the .github/ci-floor/... paths the table models. grep -rn 'scripts/v4-bootstrap-viability\|scripts/v4-m1-rust-emit' .github/ dsl/ src/ returns nothing. .github/ci-floor/v4-m1-rust-emit-probe.sh is even already typed RepoPath at src/v4/test/claim/workflow/ci_component_affected.dag:23. Adopting scripts/... would make the table unfaithful and fail the no-new-shell ratchet test (which walks the live run: bash .github/ci-floor/*.sh lines).

2. ShellScriptPath = String duplicate authority (ci.dag:391) — VALID, fixed.
Deleted the alias; shell_owner is now the canonical RepoPath (v4.lens.edit_locus, already imported at ci.dag:30).

3. CiSafetyFloorItem missing disposition (ci.dag:383) — VALID, fixed.
Added the 🟡 coproduct-dissolution tag: feature/bind #4137 §11.7.1 / dissolve-on-arrival when the dynamic affected-set+testgen safety net replaces the static floor list / forbidden open Symbol floor key.

4. ROADMAP T-PB-B row missing (test:1134) — NOT valid; no change.
ROADMAP.md does contain it: line 43 (| T-PB-B / pb_rust_tests_outside_residual_zero | Move remaining hand-authored Rust… |) and line 63 (| **T-PB-B** | pb_rust_tests_outside_residual_zero | Pure Bootstrap test floor… |). The P5 receipt is checkable against both. (The receipt now also lives in the PR body per the earlier round.)

38/38 smoke tests pass. — sent from vivid-wren-765

@briansrls briansrls 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.

Review metadata

  • Provider / model: codex / unknown
  • Commit: a369d67e · Trigger: schedule
  • Thinking: 248s wall

BLOCKING (1)

Root Cause

  • .github/workflows/ci.yml required binding step filters exclude v4_workflow_ci_class_a_shell_exception_table_first_slice → add this test to the step or rename it under an executed filter prefix.

⚠️ The new executable receipt is not wired into required CI.

/// generated `.dag` `TestClaim` execution covers the §11.7.5 shell-exception table + no-new-shell
/// ratchet (and A15 Shape-B emitted `ci.yml`), retiring this hand-Rust parse/string harness.
#[test]
fn v4_workflow_ci_class_a_shell_exception_table_first_slice() {

This comment was marked as resolved.

…o wave1_ prefix) — codex RC #4284

Valid codex BLOCKING: the new executable receipt was not enforced in required CI —
the ci_floor "M1 v4 workflow CI model/YAML binding smoke" step runs only the
`::v4_workflow_ci_m1_..._bound_to_ci_yml`, `::v4_workflow_ci_bankruptcy_tier0_`, and
`::v4_workflow_ci_wave1_` filters, and `v4_workflow_ci_class_a_shell_exception_table_first_slice`
matched none.

Fix (test-file only; no ci.yml edit — brief does not name ci.yml, avoids carrier
re-pin): rename to `v4_workflow_ci_wave1_class_a_shell_exception_table_first_slice`
so the required `::v4_workflow_ci_wave1_` floor-binding filter executes it on every
PR. Legitimate placement, not filter-gaming: the no-new-shell ratchet it enforces is
§11.7.1 item #5 — a Wave 1 safety-floor gate — even though the §11.7.5 table it
asserts is Wave 2 modeling. Doc comment documents the wiring + prefix rationale.

Verified: `cargo test -p v3-compiler --test integration
v4_workflow_ci_runner_dag_smoke_test::v4_workflow_ci_wave1_` (the exact ci.yml:255
command) now runs 3 tests incl. the renamed one, all pass; full suite 38/38.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Valid finding — fixed in 85efa0d. The receipt was indeed not enforced in required CI: the ci_floor "M1 v4 workflow CI model/YAML binding smoke" step (.github/workflows/ci.yml:253-255) runs only the ::v4_workflow_ci_m1_..._bound_to_ci_yml, ::v4_workflow_ci_bankruptcy_tier0_, and ::v4_workflow_ci_wave1_ filters, and v4_workflow_ci_class_a_shell_exception_table_first_slice matched none.

Fix: renamed the test to v4_workflow_ci_wave1_class_a_shell_exception_table_first_slice so the required ::v4_workflow_ci_wave1_ floor-binding filter executes it on every PR. I chose the rename over editing ci.yml because (a) my brief does not name .github/workflows/ci.yml, so per INVARIANTS I shouldn't hand-edit it (it would also require the carrier byte-mirror + Source-SHA re-pin), and (b) the placement is legitimate, not filter-gaming: the no-new-shell ratchet this test enforces is §11.7.1 item #5 — a Wave 1 safety-floor gate — even though the §11.7.5 table it asserts is Wave 2 modeling. The doc comment now documents the wiring and prefix rationale.

Verified with the exact ci.yml:255 command: cargo test -p v3-compiler --test integration v4_workflow_ci_runner_dag_smoke_test::v4_workflow_ci_wave1_ -- --quiet now runs 3 tests including the renamed one, all pass; full suite 38/38. — sent from vivid-wren-765

@briansrls

Copy link
Copy Markdown
Contributor Author

Already addressed on current HEAD 85efa0d (this inline finding was raised against the pre-fix a369d67). The test is now v4_workflow_ci_wave1_class_a_shell_exception_table_first_slice and is selected by the required ci_floor binding-smoke filter — verified with the exact ci.yml:255 command (cargo test ... ::v4_workflow_ci_wave1_ --list lists it; the filtered run executes 3 tests incl. this one, all pass). The P5 receipt is now fail-closed in required CI. Full detail in my top-level comment above. — sent from vivid-wren-765

@briansrls

Copy link
Copy Markdown
Contributor Author

Review metadata

  • Provider / model: openai-pro / gpt-5-5-pro
  • Commit: 85efa0d2 · Trigger: manual
  • Comparison: main @ ca13206d ... session/vivid-wren-765 @ 85efa0d2
  • Conversation: View conversation

1. Story of the diff

This PR makes §11.7.5 executable by adding a temporary, modeled exception registry for the two Class-A CI floor steps that are still shell-owned: bootstrap viability and the M1 Rust emit probe. The new src/v4/workflow/ci.dag substrate introduces a bounded CiSafetyFloorItem sum and a CiShellExceptionRow record keyed by CiStepId, with canonical carriers for shell_owner: RepoPath, replacement_upsert: CiUpsertStepSymbol, and dissolution_target: DissolutionTarget; the table is seeded with exactly the two allowed shell exceptions. chatgpt-review-3bd1f9a9-a95c-48…

chatgpt-review-3bd1f9a9-a95c-48…

The Rust side adds one same-path smoke/ratchet test to the existing v4 workflow CI harness. That test parses the CI .dag, asserts the new types/table exist, checks the two rows and canonical CiUpsertStepSymbol bindings, and attempts the no-new-shell converse: every required .github/ci-floor/*.sh invocation in ci.yml must have a table row. chatgpt-review-3bd1f9a9-a95c-48…

chatgpt-review-3bd1f9a9-a95c-48…

2. Invariant categories

  1. LAYER MODEL (substrate vs implementation).

Finding — fail-closed substrate consumer mismatch. src/v4/workflow/ci.dag:376-378 declares the load-bearing contract as equality between REQUIRED shell-owned ci-floor steps and the table rows’ step_ids: “the set of REQUIRED shell-owned ci-floor steps must equal these rows’ step_ids.” But the executable ratchet in src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1237-1241 only recognizes CI YAML lines whose trimmed text starts with run: bash .github/ci-floor/, then validates table.contains(&script). That proves only that a script path appears somewhere in the table, not that the live CI job/step is represented by a CiShellExceptionRow.step_id; it also misses block-form YAML such as run: | followed by bash .github/ci-floor/.... A new required step reusing .github/ci-floor/v4-bootstrap-viability.sh would pass without a row for its own CiStepId, so the safety-floor ratchet fails open. chatgpt-review-3bd1f9a9-a95c-48…

chatgpt-review-3bd1f9a9-a95c-48…

  1. INVARIANTS.md + modeling-discipline.md.

Finding — P3 Fail-Closed / P2 Boundary Discipline. The new table itself follows the right substrate direction by using CiStepId, RepoPath, CiUpsertStepSymbol, and DissolutionTarget rather than open string authorities, but the enforcing consumer reverse-engineers a narrow YAML spelling and checks script containment instead of consuming a structured CI fact keyed by the same step authority. INVARIANTS.md treats boundary consumers that walk storage shape or local conventions instead of declared query surfaces as drift-prone, and P3 requires missing support to fail closed rather than silently pass. chatgpt-review-6c46f2b3-8018-41…

chatgpt-review-6c46f2b3-8018-41…

  1. CODING.md.

Compliant. Apart from the blocking ratchet semantics above, the added Rust is test-only, keeps dependencies explicit through existing constants, and uses comments as load-bearing invariant/P5 headers rather than as ordinary control-flow explanation; that matches CODING.md’s allowance for boundary/invariant comments. chatgpt-review-547f3855-a142-4d…

  1. TESTING.md.

Finding — behavior-driven ratchet does not cover the behavior it names. The test name and assertions claim “no-new-shell ratchet,” but the implementation only catches one textual spelling of a shell invocation and does not assert the modeled behavior “live required (job, step, script) has a corresponding CiShellExceptionRow { step_id, shell_owner, ... }.” For a safety-floor regression test, this is not a harmless implementation detail: the failure case the test exists to prevent can still pass. The practical fix is to parse or otherwise derive the CI job/step/run structure and compare live required shell invocations against table rows by step_id + shell_owner; a temporary fallback should at least cover block-style run and duplicate-script/new-step cases. chatgpt-review-3bd1f9a9-a95c-48…

chatgpt-review-2851a509-e96b-44…

  1. LOCKED DESIGN DECISIONS.

N/A — the diff does not alter an attached locked design decision directly. It aligns with the thesis direction that CI/build orchestration is modeled in .dag; the enforcement gap is reviewed under invariants/testing and PM intent rather than as a locked-doc divergence. chatgpt-review-6b0b0e9a-79ce-44…

  1. TRACKED vs UNTRACKED DEBT.

Compliant. The temporary shapes are explicitly tracked: CiSafetyFloorItem has a bounded closed-arm disposition and deletion trigger, CiShellExceptionRow dissolves when ci.yml emits the step from replacement_upsert as runtime authority, and the Rust harness names the same-path P5 deferral plus generated .dag TestClaim retirement trigger. chatgpt-review-3bd1f9a9-a95c-48…

chatgpt-review-3bd1f9a9-a95c-48…

chatgpt-review-6c46f2b3-8018-41…

2.5. Top-down PM intent review

Finding — the first executable slice dilutes the no-new-shell ratchet. The diff’s own authority text says this slice models the exception registry consumed by the no-new-shell ratchet and that the REQUIRED shell-owned ci-floor steps must equal the rows’ step_ids at src/v4/workflow/ci.dag:376-378. The executable gate at src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1237-1241 enforces a weaker condition: exact-prefix script-path discovery plus table string containment. A worker could faithfully follow that executable gate and still add a new required shell-owned floor step with no CiShellExceptionRow for its job/step, which is exactly the semantic regression §11.7.5 is meant to prevent. chatgpt-review-3bd1f9a9-a95c-48…

chatgpt-review-3bd1f9a9-a95c-48…

3. Verdict

REQUEST_CHANGES. The substrate table is directionally good and the temporary debt is tracked, but the safety-floor ratchet’s first executable slice is under-enforced: it checks script text, not the modeled CiStepId authority, and can fail open for the main no-new-shell regression. Fixing that before merge preserves the PR’s intended contract.

@briansrls

Copy link
Copy Markdown
Contributor Author

Valid finding — addressed in a217da1. You correctly caught that the first-slice ratchet could fail open. Fixes:

1. Block-form evasion (was: only run: bash … inline lines). The ratchet now scans every ci.yml line containing bash for a .github/ci-floor/*.sh token, so a block-scalar run: | body ( bash .github/ci-floor/foo.sh) is caught regardless of YAML spelling.

2. Containment → bijection (was: table.contains(script)). It now enforces a bidirectional 1:1: every required ci-floor script must have a row, and distinct-required-script-count == CiShellExceptionRow count. A new required shell (or an extra/stale row) breaks the bijection and fails closed, rather than passing on mere string containment.

3. Over-claiming contract comment (ci.dag:376-378). Rewrote it to separate INTENDED (step_id-set equality) from ENFORCED-today (the path-keyed, block-form-safe, count-exact bijection), and to name the RESIDUAL explicitly.

On the residual you flagged — keying on (job, step) CiStepId vs script path: I could not fully close this in the harness because ci.yml's step→CiStepId mapping isn't available in string-checkable form here (the table's step_id is a CiJobId/symbol, not the ci.yml step name). Rather than fake it, I named it as a tracked residual in both the test and the ci.dag comment, with the dissolution trigger = the generated .dag CI step model (same trigger as this harness's overall retirement). So a second step reusing an already-listed script is the one case still not distinguished by step_id; the new-script and block-form cases — the primary no-new-shell regressions — now fail closed.

Verified: required ::v4_workflow_ci_wave1_ filter runs 3 tests incl. this one; full suite 38/38. — sent from vivid-wren-765

@briansrls briansrls 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.

Review metadata

  • Provider / model: codex / unknown
  • Commit: a217da1e · Trigger: schedule
  • Thinking: 288s wall

BLOCKING (1)

Root Cause

  • src/v4/workflow/ci.dag the section 11.7.5 table and verifier were modeled against a .github/ci-floor path convention that this PR does not make runtime authority -> bind shell_owner and the scanner to the live scripts/ authorities or move the CI invocations and files in the same PR.

ROADMAP — Incomplete

  • T-PB-B: ROADMAP.md still has no T-PB-B / pb_rust_tests_outside_residual_zero row, so the same-path P5 deferral remains uncheckable.

⚠️ The required CI ratchet is now wired, but it is wired to paths that are not the live required shell authorities.

if !line.contains("bash ") {
continue;
}
if let Some(idx) = line.find(".github/ci-floor/") {

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.

Invariant violation: BLOCKING: The new ratchet only scans .github/ci-floor/, but the live required floor shell invocations are still .github/workflows/ci.yml:155 and .github/workflows/ci.yml:162 scripts/ paths, so the executable receipt is not faithful or fail-closed.

@briansrls

Copy link
Copy Markdown
Contributor Author

Both findings in this codex round (top-level + inline at test:1242) are factually incorrect against the current PR head a217da1 — verified, no change warranted.

"live required floor shells are scripts/ paths at ci.yml:155 and :162" — FALSE.
grep -n 'scripts/' .github/workflows/ci.yml returns nothing — there are zero scripts/ references in ci.yml. Lines 155 and 162 are inside the ci_floor job's toolchain-isolation step (run: | setting CARGO_HOME/RUSTUP_HOME/CARGO_BUILD_JOBS) — not shell floor invocations at all. The actual required floor invocations are :240 run: bash .github/ci-floor/v4-m1-rust-emit-probe.sh and :250 run: bash .github/ci-floor/v4-bootstrap-viability.sh — exactly what shell_owner and the scanner target. scripts/v4-bootstrap-viability.sh / scripts/v4-m1-rust-emit-probe.sh do not exist (ls → No such file; grep across .github/ dsl/ src/ → empty). The ratchet is faithful and fail-closed against the live authorities. This is the third time this scripts/ claim has been raised against a tree state that does not exist here; it was previously verified false and confirmed by the CI manager.

"ROADMAP has no T-PB-B / pb_rust_tests_outside_residual_zero row" — FALSE.
Present at ROADMAP.md:43 (| T-PB-B / pb_rust_tests_outside_residual_zero | Move remaining hand-authored Rust… |) and :63 (| **T-PB-B** | pb_rust_tests_outside_residual_zero | Pure Bootstrap test floor… |). The same-path P5 deferral is checkable against both, and the receipt also lives in the PR body.

Verified on a217da1: required ::v4_workflow_ci_wave1_ filter runs 3 tests incl. the ratchet, all pass; full suite green. — sent from vivid-wren-765

@briansrls briansrls 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.

Review metadata

  • Provider / model: codex / unknown
  • Commit: b95e23d9 · Trigger: schedule
  • Thinking: 276s wall

BLOCKING (1)

Root Cause

  • src/v4/workflow/ci.dag bootstrap exception rows are chosen by bootstrap-like names instead of a live CI step→CiStepId/CiUpsertStep mapping → bind this row to v2_compile_src_v4/ci_upsert_v2_compile_src_v4 or introduce the actual bootstrap-viability upsert before listing the exception.

⚠️ One new bootstrap mapping issue remains in the shell-exception table.

Comment thread src/v4/workflow/ci.dag
// openai-pro #4284): the gate keys on script path, not the modeled `(job, step)` `CiStepId`, since
// ci.yml's step→`CiStepId` mapping is not yet string-checkable; a *second* step reusing a listed
// script is not yet distinguished by `step_id`. Dissolves when the generated `.dag` CI step model
// lets the ratchet compare live `(job, step, script)` against `step_id + shell_owner` directly.

This comment was marked as resolved.

briansrls and others added 2 commits June 2, 2026 08:31
…y, not bootstrap_smoke (codex RC #4284)

Valid codex BLOCKING (P1/P2): the bootstrap row was bound by NAME ("bootstrap") to
`v2_bootstrap_smoke_execution` / `ci_upsert_v2_bootstrap_smoke_execution`, but the live
`.github/ci-floor/v4-bootstrap-viability.sh` is the v2→v4 FULL COMPILE over src/v4
(script header: "v2-compiler full compile over src/v4"; ci.yml step "v2 -> v4 bootstrap
compile (fail-closed full)"), which is modeled by `v2_compile_src_v4` /
`ci_upsert_v2_compile_src_v4` (verify `BootstrapStageCompile { produces: v4_stage0_binary }`).
So the row pointed at the wrong replacement authority.

Fix: rebind the bootstrap row's step_id AND replacement_upsert to v2_compile_src_v4 /
ci_upsert_v2_compile_src_v4 — bound by what the script DOES, not name resemblance.
shell_owner / protects_floor (BootstrapMinimalViability) / dissolution_target unchanged.
Test needles updated to match; ci_upsert_v2_compile_src_v4 confirmed a declared
CiUpsertStepSymbol authority (ci.dag:1105).

Bijection intact (still 2 scripts ↔ 2 rows, distinct step_ids: v2_compile_src_v4 +
m1_rust_emit_probe_execution). Required `::v4_workflow_ci_wave1_` filter runs 3 tests
incl. the ratchet; full suite 38/38.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Valid finding — fixed in 0f26e16. You're right: I bound the bootstrap row by name, not by what the script does.

Evidence: .github/ci-floor/v4-bootstrap-viability.sh header says "Fail-closed v4 bootstrap gate: v2-compiler full compile over src/v4", and its ci.yml step is "v2 -> v4 bootstrap compile (fail-closed full)". That is the v2→v4 compile of src/v4, modeled by v2_compile_src_v4 / ci_upsert_v2_compile_src_v4 (verify BootstrapStageCompile { produces: v4_stage0_binary }) — not the lighter v2_bootstrap_smoke_execution.

Fix: rebound the bootstrap row's both step_id and replacement_upsert to v2_compile_src_v4 / ci_upsert_v2_compile_src_v4 (confirmed a declared CiUpsertStepSymbol authority at ci.dag:1105). shell_owner, protects_floor: BootstrapMinimalViability, and dissolution_target are unchanged. Bijection still holds: 2 scripts ↔ 2 rows with distinct step_ids (v2_compile_src_v4 + m1_rust_emit_probe_execution). Updated the test needles to match. Required ::v4_workflow_ci_wave1_ filter runs 3 tests incl. the ratchet; full suite 38/38.

(The deeper root cause you named — choosing by name instead of a live CI-step→CiStepId mapping — is the same residual the ratchet already documents: ci.yml step→CiStepId isn't string-derivable here, so this row was hand-mapped. I've now hand-mapped it correctly by the script's actual behavior.) — sent from vivid-wren-765

@briansrls briansrls 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.

Review metadata

  • Provider / model: codex / unknown
  • Commit: 0f26e16b · Trigger: schedule
  • Thinking: 335s wall

⚠️ Prior blocking path/P5 receipt comments remain unresolved; I found no additional new blocking issue beyond those.

@briansrls

Copy link
Copy Markdown
Contributor Author

This review states it found "no additional new blocking issue" and only re-asserts the prior path/P5-receipt comments. Those were already verified false and resolved — re-confirmed on this exact HEAD (0f26e16):

  • scripts/ paths: grep -c 'scripts/' .github/workflows/ci.yml = 0. The live floor invocations are .github/ci-floor/v4-m1-rust-emit-probe.sh (:240) and .github/ci-floor/v4-bootstrap-viability.sh (:250); no scripts/ floor scripts exist. The ratchet binds those live paths.
  • P5 / ROADMAP T-PB-B: present at ROADMAP.md:43 and :63 (grep -c pb_rust_tests_outside_residual_zero ROADMAP.md = 2); the receipt is also in the PR body.

These same two claims were already refuted with line evidence, confirmed by the CI manager, and codex itself APPROVED them on manual re-review #25591 (b95e23d, carried forward unchanged to 0f26e16). The one genuinely new+valid codex finding this cycle (bootstrap row → v2_compile_src_v4 authority) was fixed in 0f26e16. No open blocking item remains; current HEAD has claude+cursor APPROVE, no RC. — sent from vivid-wren-765

@briansrls

Copy link
Copy Markdown
Contributor Author

Review metadata

  • Provider / model: openai-pro / gpt-5-5-pro
  • Commit: 0f26e16b · Trigger: manual
  • Comparison: main @ 6cb118c4 ... session/vivid-wren-765 @ 0f26e16b
  • Conversation: View conversation

1. Story of the diff

This PR turns the Class-A shell exception policy into explicit src/v4/workflow/ci.dag data instead of leaving it as prose: it adds a closed CiSafetyFloorItem carrier, a CiShellExceptionRow record keyed by CiStepId, RepoPath, canonical CiUpsertStepSymbol, and DissolutionTarget, then populates the first two temporary rows for bootstrap viability and M1 Rust emit. The data shape is explicitly temporary: each row points at the CiUpsertStep authority that retires it once CI YAML is emitted from the modeled upsert rather than from the shell script. The Rust integration addition is the first executable slice: it parses ci.dag, checks the table and canonical upsert references, scans ci.yml for .github/ci-floor/*.sh invocations, and tries to enforce a path-keyed no-new-shell bijection until the generated CI step model can compare (job, step, script) directly. chatgpt-review-5383e618-3411-43…

chatgpt-review-5383e618-3411-43…

chatgpt-review-5383e618-3411-43…

2. Invariant categories

  1. LAYER MODEL (substrate vs implementation).

Compliant — this does touch v4 workflow substrate, and the core modeled row uses existing canonical carriers rather than inventing parallel leaves: src/v4/workflow/ci.dag:415-425 declares CiShellExceptionRow { step_id: CiStepId, shell_owner: RepoPath, replacement_upsert: CiUpsertStepSymbol, dissolution_target: DissolutionTarget }. That is the right substrate-vs-implementation split; the issue below is in the temporary executable ratchet, not the row type itself. chatgpt-review-5383e618-3411-43…

  1. INVARIANTS.md + modeling-discipline.md.

Finding — P3 fail-closed / P2 verification-as-substrate-consumer. src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1265 uses table.contains(script.as_str()) as the forward ratchet proof that each required CI-floor shell has a CiShellExceptionRow. But table is just the raw substring after data ci_class_a_shell_exceptions: (src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1164-1170), and the diff itself places the bootstrap script path in a comment inside that slice at src/v4/workflow/ci.dag:435, before the actual shell_owner field at src/v4/workflow/ci.dag:441. That means the gate can pass with the required script mentioned only in prose while the row’s shell_owner is stale or wrong, so the no-new-shell ratchet fails open. The fix is to consume parsed row fields or at least match the field-level spelling, for example shell_owner: "{script}", after stripping comments. chatgpt-review-5383e618-3411-43…

chatgpt-review-5383e618-3411-43…

chatgpt-review-5383e618-3411-43…

  1. CODING.md.

Compliant — the changed Rust is test harness code rather than a new production API; it adds no methods, builders, global mutable state, or hidden dependency surface. The long comments are mostly load-bearing boundary/invariant notes explaining the temporary CI authority split, which CODING.md permits for non-obvious invariants and automation boundaries. The blocking concern is not comment volume; it is the comment-sensitive assertion above. chatgpt-review-3c90c6af-995f-4d…

  1. TESTING.md.

Finding — behavior-driven ratchet is not pinned to the behavior field. The added test is at the right level in concept because the subject is the CI model/YAML binding, and the temporary Rust header documents the P5/PB-B dissolution path. However, src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1265 does not actually assert the behavior it names: “required shell has an exception row” becomes “the script path appears anywhere in the table text.” Because comments are inside the searched table slice, this is not a hermetic structural assertion on CiShellExceptionRow.shell_owner. chatgpt-review-5383e618-3411-43…

chatgpt-review-5383e618-3411-43…

  1. LOCKED DESIGN DECISIONS.

Compliant — no supplied locked design decision is altered. The PR moves in the thesis direction that CI/build orchestration is modeled as .dag workflow data, and it does not introduce a new compiler render target or hand-edited ci.yml authority. chatgpt-review-cec7e6cf-7143-41…

  1. TRACKED vs UNTRACKED DEBT.

Compliant — the temporary substrate and harness debt is explicitly tracked: src/v4/workflow/ci.dag:395-401 names the path-keyed residual and its generated-CI-step-model dissolution trigger; src/v4/workflow/ci.dag:406 and src/v4/workflow/ci.dag:414 tag the coproduct/table dissolution; the Rust harness header names the PB-B same-path deferral and .dag TestClaim retirement trigger. The comment-sensitive contains bug is not an accepted tracked bridge, but the scaffold itself has documentation, bounds, and dissolution triggers. chatgpt-review-5383e618-3411-43…

chatgpt-review-5383e618-3411-43…

2.5. Top-down PM intent review

Finding. The PM-level intent is clear in the diff itself: src/v4/workflow/ci.dag:394-401 says the intended contract is that required shell-owned CI-floor steps equal the exception rows, with a temporary path-keyed bijection until the generated CI step model can compare against step_id + shell_owner. The executable enforcement at src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1265 dilutes that into raw text containment over a comment-inclusive slice, so a worker could faithfully follow the test while leaving the modeled shell_owner wrong. That undercuts the highest-level purpose of this PR: making the shell exception table the reliable no-new-shell safety-floor authority. chatgpt-review-5383e618-3411-43…

chatgpt-review-5383e618-3411-43…

3. Verdict

REQUEST_CHANGES

The modeled table shape is directionally right and well-tracked, but the first executable ratchet is not fail-closed: it can satisfy a required shell by finding the path in comments rather than in CiShellExceptionRow.shell_owner. Tightening the assertion to parsed/field-level row data should make this approvable.

…clusive containment (openai-pro RC #4284)

Valid openai-pro REQUEST_CHANGES (P2/P3 fail-open): the forward ratchet used
`table.contains(script)` over the raw `ci_class_a_shell_exceptions` slice, which
INCLUDES comments. The bootstrap row's comment documents its script path
(`.github/ci-floor/v4-bootstrap-viability.sh`), so the gate could pass on the path
appearing in prose while the actual `shell_owner` field was stale/wrong — i.e. the
no-new-shell ratchet failed open, defeating its purpose.

Fix: match the field spelling `shell_owner: "{script}"` instead of bare containment,
so the assertion is pinned to `CiShellExceptionRow.shell_owner` and a path mentioned
only in a comment no longer satisfies it. Updated the ci.dag ENFORCED-today contract
note to say the bijection is keyed on the shell_owner field.

Required `::v4_workflow_ci_wave1_` filter runs 3 tests incl. the ratchet; full 38/38.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Valid finding — fixed in 55d269e. You're right: the forward ratchet was table.contains(script) over the raw ci_class_a_shell_exceptions slice, which includes comments — and the bootstrap row's comment documents its script path, so the gate could pass on the path in prose while shell_owner was stale/wrong (fail-open).

Fix: the forward check now matches the field spelling shell_owner: "{script}" instead of bare containment, pinning it to CiShellExceptionRow.shell_owner. A path appearing only in a comment no longer satisfies the ratchet. Updated the ci.dag ENFORCED-today contract note to state the bijection is keyed on the shell_owner field (block-form-safe + count-exact still hold). Required ::v4_workflow_ci_wave1_ filter runs 3 tests incl. the ratchet; full suite 38/38. — sent from vivid-wren-765

@briansrls

Copy link
Copy Markdown
Contributor Author

Review metadata

  • Provider / model: openai-pro / gpt-5-5-pro
  • Commit: 55d269e7 · Trigger: manual
  • Comparison: main @ 6cb118c4 ... session/vivid-wren-765 @ 55d269e7
  • Conversation: View conversation

1. Story of the diff

This PR introduces the first executable model for Wave 2 §11.7.5’s temporary Class-A shell exception table. The .dag side adds a closed CiSafetyFloorItem carrier and a CiShellExceptionRow record keyed by existing authorities: CiStepId, canonical RepoPath, canonical CiUpsertStepSymbol, and DissolutionTarget; the table currently contains the two allowed shell-owned floor steps, bootstrap viability and M1 rust emit. The Rust side extends the existing v4 workflow CI smoke harness to parse ci.dag, assert the table shape and two rows, bind replacement upserts to declared CiUpsertStepSymbol data, and enforce a no-new-shell ratchet against .github/workflows/ci.yml. chatgpt-review-2ce743a0-d512-44…

chatgpt-review-2ce743a0-d512-44…

chatgpt-review-2ce743a0-d512-44…

2. Invariant categories

  1. LAYER MODEL (substrate vs implementation). — Compliant.

The diff does touch v4 workflow substrate, but it models the temporary exception table as typed .dag data rather than a parallel Rust-only registry: CiShellExceptionRow carries step_id: CiStepId, shell_owner: RepoPath, replacement_upsert: CiUpsertStepSymbol, and dissolution_target: DissolutionTarget. That is the right substrate posture for single authority and illegal-state pressure; no new Dag connective or behavior substrate is introduced. chatgpt-review-2ce743a0-d512-44…

  1. INVARIANTS.md + modeling-discipline.md. — Finding.

P3 Fail-Closed / P2 Boundary Discipline: src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1241 gates on if !line.contains("bash "), and src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1244 then accepts any .github/ci-floor/ occurrence in that line. Because this loop scans every line of ci.yml without excluding YAML comments or otherwise proving it is inside an actual run command, a comment-only line such as # bash .github/ci-floor/v4-bootstrap-viability.sh would be treated as a live required invocation. That also satisfies the earlier liveness assertion at src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1229, which uses raw CI_YML.contains("bash {script}"). The declared contract is that required shell-owned ci-floor invocations equal the table rows and a new unlisted required shell fails closed; this implementation can pass on comment containment, so the ratchet still has a fail-open path. INVARIANTS makes fail-closed and single authority first principles, not advisory style. chatgpt-review-2ce743a0-d512-44…

chatgpt-review-2ce743a0-d512-44…

chatgpt-review-2ce743a0-d512-44…

chatgpt-review-ca84adba-304f-4a…

Required fix: derive the live set only from actual YAML run command content, or at minimum skip comment-only lines and reuse the same parsed live set for both row-liveness and bijection checks instead of mixing raw contains with the extracted script list.

  1. CODING.md. — Compliant.

The new Rust is test-edge code over constants, not a production API surface. The heavy comments are mostly load-bearing boundary/receipt text: why this is same-path P5 test debt, why wave1_ wiring matters, why field-level matching is required, and what residual remains. CODING.md allows comments for non-obvious boundaries, invariants, external constraints, and historical/load-bearing context. The scanner correctness issue is covered above; I do not see a separate coding-style blocker. chatgpt-review-2ce743a0-d512-44…

chatgpt-review-2ce743a0-d512-44…

chatgpt-review-1ed036f2-63b8-47…

  1. TESTING.md. — Finding.

Same blocker as above, from the testing angle: this new smoke test is the merge-visible no-new-shell ratchet, but it does not faithfully test the behavior it names because it treats arbitrary line containment as evidence of a live required YAML invocation. TESTING.md asks tests to pin caller-visible behavior and avoid implementation details; here the intended behavior is “live required ci-floor shell invocation,” while the test pins “some line contains bash plus .github/ci-floor/.” chatgpt-review-2ce743a0-d512-44…

chatgpt-review-a2f09ff3-a5c0-4b…

  1. LOCKED DESIGN DECISIONS. — N/A.

I do not see this diff altering a locked substrate shape or locked design decision. It references #4137/T-24/T-PB-B and implements a bounded workflow model slice; the PM-level mismatch is the executable scanner, addressed in §2.5.

  1. TRACKED vs UNTRACKED DEBT. — Compliant.

The temporary shapes are explicitly tracked: the Rust harness is a same-path SG-0 expansion with a named T-PB-B / pb_rust_tests_outside_residual_zero dissolution, the .dag CiSafetyFloorItem and CiShellExceptionRow carriers carry yellow dissolution tags, and the path-keyed ratchet residual is bounded with a named trigger: generated .dag CI step modeling that can compare live (job, step, script) against step_id + shell_owner. The comment-line fail-open above is not acceptable “debt”; it is a correctness bug in the current ratchet. chatgpt-review-2ce743a0-d512-44…

chatgpt-review-2ce743a0-d512-44…

chatgpt-review-2ce743a0-d512-44…

2.5. Top-down PM intent review

Finding. The high-level intent is preserved in the model but diluted in the executable gate. The authority text says the PR’s intended contract is that REQUIRED shell-owned ci-floor steps equal the table’s modeled rows and that “a new unlisted required shell fails CLOSED.” The implementation then scans arbitrary CI YAML lines for bash and .github/ci-floor/, so a comment can stand in for a live required invocation and keep a stale row green. For a PM/executive owner, that means the PR’s first executable safety-floor ratchet is not yet enforcing the semantic no-new-shell rule it claims to enforce. chatgpt-review-2ce743a0-d512-44…

chatgpt-review-2ce743a0-d512-44…

3. Verdict

REQUEST_CHANGES. The .dag modeling is well-shaped and the temporary-debt receipts are mostly disciplined, but the core executable value of the PR is a fail-closed no-new-shell ratchet. Since the current scanner can pass on comment-only containment, that ratchet needs to be tightened before merge.

@briansrls

Copy link
Copy Markdown
Contributor Author

Valid finding — fixed in b0cdb45. Symmetric to the prior table-side fix, this was the ci.yml-side comment hole: the scan counted any line with bash + .github/ci-floor/, and cond-1 used raw CI_YML.contains("bash {script}") — so a commented-out # bash .github/ci-floor/v4-bootstrap-viability.sh would count as a live required invocation.

Fix: parse the live set comment-safely — skip comment-only lines (trim_start starts with #) and strip inline # … trailers — and reuse that single parsed set for both the row-liveness (cond 1) check and the bijection, replacing the raw contains. Block-form run: | bodies are still caught; commented invocations no longer are. Updated the ci.dag ENFORCED-today note (comment-safe live set). Required ::v4_workflow_ci_wave1_ filter runs 3 tests incl. the ratchet; full suite 38/38. — sent from vivid-wren-765

@briansrls briansrls 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.

Review metadata

  • Provider / model: codex / unknown
  • Commit: 55d269e7 · Trigger: schedule
  • Thinking: 241s wall

⚠️ Prior blocking comments 3338742904, 3338742912, and 3339441780 still appear unresolved; I found no additional new blocking concerns.

@briansrls

Copy link
Copy Markdown
Contributor Author

This codex review is on the superseded SHA 55d269e and explicitly found "no additional new blocking concerns" — it only re-lists prior comments. All of those are resolved on the current HEAD (b0cdb45):

  • The fail-open ratchet concerns (table-side comment-inclusive containment, then ci.yml-side comment-inclusive scan) were fixed: shell_owner-field pinning (55d269e) + comment-safe single live-set parsing (b0cdb45).
  • The path/ROADMAP comments were verified false (no scripts/ paths in ci.yml; ROADMAP T-PB-B present at :43/:63) and were already approved by codex on manual re-review #25591.

No open blocking item remains; current HEAD has claude+cursor APPROVE, no RC. — sent from vivid-wren-765

@briansrls

Copy link
Copy Markdown
Contributor Author

Review metadata

  • Provider / model: openai-pro / gpt-5-5-pro
  • Commit: 0322519a · Trigger: manual
  • Comparison: main @ 09bdd09f ... session/vivid-wren-765 @ 0322519a
  • Conversation: View conversation

1. Story of the diff

This PR turns the temporary Class-A shell exception policy into modeled CI data and wires a first executable ratchet around it. src/v4/workflow/ci.dag adds a bounded CiSafetyFloorItem enum, a CiShellExceptionRow record, two dissolution-target symbols, and exactly two table rows: the bootstrap viability shell and the M1 Rust emit probe shell. The rows bind each shell script to a modeled CiStepId, a canonical RepoPath shell owner, a CiSafetyFloorItem, the retiring CiUpsertStepSymbol, and a structural DissolutionTarget (src/v4/workflow/ci.dag:408-462). The new Rust smoke test parses the CI model, checks those model pieces exist, checks the two rows and canonical upsert symbols, and then scans ci.yml for live .github/ci-floor/*.sh invocations so unmodeled required shell scripts should trip the gate (src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1123-1304). chatgpt-review-d760f23d-124d-43…

chatgpt-review-d760f23d-124d-43…

2. Invariant categories

  1. LAYER MODEL (substrate vs implementation). Compliant — this touches the workflow .dag model, not just file-scoped Rust, and the new row type reuses existing carriers instead of inventing a parallel representation: step_id: CiStepId, shell_owner: RepoPath, replacement_upsert: CiUpsertStepSymbol, and dissolution_target: DissolutionTarget at src/v4/workflow/ci.dag:417-427. chatgpt-review-d760f23d-124d-43…
  2. INVARIANTS.md + modeling-discipline.md. Finding — P3 Fail-Closed / no-new-shell ratchet. At src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1243-1248, the live-shell scanner extracts from .github/ci-floor/ until whitespace and then only records the script if leaf.ends_with(".sh"). That silently drops valid live invocations such as bash ".github/ci-floor/new.sh" or bash .github/ci-floor/new.sh; echo ok, because the collected leaf ends with .sh" or .sh;, so the later bijection never sees the new shell. The surrounding model claims a new unlisted required shell “fails CLOSED” (src/v4/workflow/ci.dag:395-403), but this parser path fails open. Fix by normalizing quoted/shell-punctuated path tokens, or more fail-closed: once a non-comment bash line contains .github/ci-floor/, reject any spelling the ratchet cannot canonicalize rather than ignoring it. chatgpt-review-d760f23d-124d-43…

chatgpt-review-d760f23d-124d-43…

  1. CODING.md. Compliant — the new Rust code is test-harness logic, not a production object/method surface, and the unusually long comments are load-bearing boundary/receipt comments explaining temporary authority, required-CI wiring, and dissolution triggers. The parser bug above is an invariant/test-behavior issue, not a style-only concern.
  2. TESTING.md. Finding — same blocking ratchet gap, not a separate issue. The PR adds the right kind of executable receipt for this change: a same-path integration smoke test for the CI model/YAML binding. But the test’s named behavior is “every REQUIRED ci-floor shell invocation in ci.yml must carry a row,” while src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1243-1248 can miss syntactically valid live shell invocations and still pass. Because this is the safety-floor regression test, it needs to fail closed on unrecognized live .github/ci-floor/*.sh spellings before merge. chatgpt-review-d760f23d-124d-43…
  3. LOCKED DESIGN DECISIONS. N/A — no attached locked design doc is changed, and I did not find a concrete diff-cited divergence from the thesis or invariant authority beyond the ratchet fail-closed issue already called out.
  4. TRACKED vs UNTRACKED DEBT. Compliant — the new temporary shapes are explicitly tracked: CiSafetyFloorItem and CiShellExceptionRow carry 🟡 coproduct-dissolution tags and named dissolve-on-arrival triggers (src/v4/workflow/ci.dag:408-416), and the path-keyed ratchet residual is documented with a bound and dissolution trigger both in the model comment (src/v4/workflow/ci.dag:399-403) and in the Rust test (src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1297-1303). chatgpt-review-d760f23d-124d-43…

chatgpt-review-d760f23d-124d-43…

2.5. Top-down PM intent review

Finding — semantic dilution of the no-new-shell safety floor. The PM-level intent in this slice is that the exception table plus ratchet make “a new unlisted required shell” fail closed; the diff states that explicitly in src/v4/workflow/ci.dag:395-403. The implementation does not faithfully preserve that intent because src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1243-1248 can observe a live bash line containing .github/ci-floor/ and then discard it when the token has normal shell/YAML punctuation. A worker following the modeled contract could reasonably believe every required shell is guarded, while the executable gate only guards the current unquoted/simple spelling. chatgpt-review-d760f23d-124d-43…

chatgpt-review-d760f23d-124d-43…

3. Verdict

REQUEST_CHANGES

The modeled table shape is directionally right and the temporary debt is well documented, but the executable no-new-shell ratchet is not actually fail-closed for valid shell spellings. Since this is a required safety-floor gate, the scanner needs to canonicalize or reject unrecognized live .github/ci-floor/*.sh invocations before the PR lands.

… on unrecognized spelling (openai-pro RC #4284)

Valid openai-pro REQUEST_CHANGES (P3 fail-open): the live-shell scanner took the path
token until whitespace then `if leaf.ends_with(".sh")`, silently DROPPING punctuated/
quoted spellings — `bash ".github/ci-floor/x.sh"` (token ends `.sh"`) or
`bash .github/ci-floor/x.sh; echo` (ends `.sh;`) — so a new required shell in those
spellings would never reach the bijection (fail-open).

Fix: canonicalize the token by reading until whitespace OR a shell/YAML separator/quote
(`"' ; & | ) ``), and FAIL CLOSED — assert — on any non-comment `bash` line referencing
`.github/ci-floor/` that does not canonicalize to a `*.sh` path, rather than silently
ignoring it. Now quoted, `;`/`&`/`|`-suffixed, and subshell spellings are all caught,
and an unrecognized spelling trips the gate. ci.dag contract note updated.

Required `::v4_workflow_ci_wave1_` filter runs 3 tests incl. the ratchet; full 38/38.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Valid finding — fixed in 62e1b13, using your stronger "fail-closed on unrecognized spelling" suggestion. The scanner took the path token until whitespace then if leaf.ends_with(".sh"), silently dropping bash ".github/ci-floor/x.sh" (token …x.sh") and bash .github/ci-floor/x.sh; echo (token …x.sh;).

Fix: canonicalize the token by reading until whitespace or a shell/YAML separator/quote (\"' ; & | ) ``), and **fail CLOSED** — assert!— on any non-commentbashline referencing.github/ci-floor/that does not canonicalize to a*.shpath, instead of ignoring it. So quoted,;/&/|-suffixed, and subshell spellings now all canonicalize into the live set, and a spelling the canonicalizer can't handle trips the gate rather than escaping it. ci.dag ENFORCED-today note updated. Required ::v4_workflow_ci_wave1_` filter runs 3 tests incl. the ratchet; full suite 38/38. — sent from vivid-wren-765

@briansrls

Copy link
Copy Markdown
Contributor Author

Review metadata

  • Provider / model: openai-pro / gpt-5-5-pro
  • Commit: 62e1b134 · Trigger: manual
  • Comparison: main @ 09bdd09f ... session/vivid-wren-765 @ 62e1b134
  • Conversation: View conversation

1. Story of the diff

This PR creates the first executable model for the temporary Class-A CI shell exception surface. In src/v4/workflow/ci.dag, it introduces a closed CiSafetyFloorItem carrier and a CiShellExceptionRow record that ties each still-shell-owned required floor step to a modeled CiStepId, canonical RepoPath shell owner, canonical CiUpsertStepSymbol replacement authority, and structural DissolutionTarget; the two populated rows are the bootstrap viability script and the M1 Rust emit probe script. chatgpt-review-7176c981-eca6-48…

The Rust side adds a same-file smoke ratchet in v4_workflow_ci_runner_dag_smoke_test.rs: it parses ci.dag, confirms the type/table shape, checks the two exception rows and their upsert/dissolution bindings, then scans ci.yml for required .github/ci-floor/*.sh invocations and asserts a 1:1 match against CiShellExceptionRow.shell_owner. The intent is explicitly transitional: this harness is documented as a same-path hand-Rust P5 receipt until generated .dag TestClaim execution and generated CI modeling can retire it. chatgpt-review-7176c981-eca6-48…

2. Invariant categories

  1. LAYER MODEL (substrate vs implementation).

Compliant — this diff does touch workflow substrate, and the main modeling choice uses declared carriers rather than parallel strings: src/v4/workflow/ci.dag:419-428 defines CiShellExceptionRow with step_id: CiStepId, shell_owner: RepoPath, replacement_upsert: CiUpsertStepSymbol, and dissolution_target: DissolutionTarget, preserving single-authority leaf types for the temporary exception table. chatgpt-review-7176c981-eca6-48…

  1. INVARIANTS.md + modeling-discipline.md.

Finding — src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1239: if !line.contains("bash ") { continue; }

The no-new-shell ratchet is intended to fail closed on required ci-floor shell invocations: the .dag contract says the enforced surface is a bijection over required .github/ci-floor/*.sh invocations and that “an unrecognizable ci-floor spelling trips the gate” / “a new unlisted required shell fails CLOSED” (src/v4/workflow/ci.dag:395-400). But the scanner first filters out every line that does not contain the literal substring "bash ", before it checks for .github/ci-floor/. A live required invocation spelled as sh .github/ci-floor/new.sh, ./.github/ci-floor/new.sh, source .github/ci-floor/new.sh, or another non-bash shell form would be silently skipped, never canonicalized, never added to ci_floor_scripts, and therefore never compared to the exception table. That violates P3 fail-closed / no-new-shell semantics: unrecognized live shell ownership must trip the ratchet, not disappear from the live set.

  1. CODING.md.

Compliant — the Rust addition stays inside the existing integration harness, uses local data flow (CI_DAG, CI_YML, ci_floor_scripts) without adding hidden state or new production APIs, and the unusually long comments are load-bearing receipts/boundary notes: P5 same-path SG-0 status, required-CI wiring, and a named residual. The one blocking issue above is semantic fail-open behavior, not style.

  1. TESTING.md.

Finding — src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1239: if !line.contains("bash ") { continue; }

The test claims to enforce “every REQUIRED ci-floor shell invocation in ci.yml must carry a row here” (src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1124-1127) and later asserts the bijection between live ci-floor scripts and exception rows. Because the live-set extractor excludes non-bash lines before detecting .github/ci-floor/, the regression test would pass while a new required ci-floor script using a different live shell spelling remains unmodeled. For this PR, the test is the merge-visible ratchet, so it needs to scan for .github/ci-floor/ first and either include recognized invocations or fail closed on any unrecognized invocation form.

  1. LOCKED DESIGN DECISIONS.

N/A — the diff references roadmap/design targets such as T-24, A15, and §11.7.5, but it does not modify a locked design document or introduce a concrete changed line that diverges from a locked decision.

  1. TRACKED vs UNTRACKED DEBT.

Compliant — the temporary shapes are bounded and carry dissolution triggers: the test header says the same-path hand-Rust harness retires when generated .dag TestClaim execution covers this table and ratchet; the .dag comments say CiSafetyFloorItem deletes when the dynamic affected-set/testgen safety net replaces the static floor list, and CiShellExceptionRow rows delete when ci.yml emits the relevant step_id from replacement_upsert as runtime authority; the residual path-keyed ratchet explicitly dissolves when generated CI step modeling can compare live (job, step, script) against step_id + shell_owner.

2.5. Top-down PM intent review

Finding — PM intent is diluted by the same bash gate. The high-level direction is that CI/build orchestration is modeled as .dag workflow data, and this PR’s own .dag contract says the enforced surface is the required .github/ci-floor/*.sh invocation set, with unrecognizable spellings failing closed (src/v4/workflow/ci.dag:395-400). The implementation narrows that to “required ci-floor invocations that happen to contain the literal substring bash ” at src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs:1239, which would let a worker add a new required ci-floor script in a non-bash spelling and still satisfy the table ratchet. That changes the product promise from “no new required shell floor without a modeled exception row” to “no new bash -spelled required shell floor without a modeled exception row,” which is exactly the kind of semantic dilution this review section is meant to catch. chatgpt-review-7176c981-eca6-48…

3. Verdict

REQUEST_CHANGES

The .dag modeling and dissolution receipts are pointed in the right direction, but the central no-new-shell ratchet has a fail-open path for non-bash ci-floor invocations. Fix the live-set extraction so any live .github/ci-floor/*.sh reference is either modeled into the bijection or rejected as an unrecognized required shell spelling before merge.

…form-agnostic) (openai-pro RC #4284)

Valid openai-pro REQUEST_CHANGES (P3 fail-open): the scanner filtered
`if !line.contains("bash ") { continue; }` BEFORE checking `.github/ci-floor/`, so a
required floor step spelled `sh .github/ci-floor/new.sh`, `./.github/ci-floor/new.sh`,
or `source .github/ci-floor/new.sh` would be skipped — never canonicalized, never in
the live set, never compared to the table (fail-open).

Fix: drop the `bash ` pre-filter; key on the `.github/ci-floor/` PATH for every
non-comment line. Any ci-floor reference is treated as a live invocation, canonicalized,
and must yield a modeled `.sh` (else the existing fail-closed assert trips). Now bash,
sh, ./, source, and bare spellings are all caught. ci.dag contract note updated
(shell-form-agnostic). Verified no false trips: ci.yml references ci-floor only in the
two real `.sh` invocations.

Required `::v4_workflow_ci_wave1_` filter runs 3 tests incl. the ratchet; full 38/38.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Valid finding — fixed in 6259d49. The scanner filtered if !line.contains("bash ") before checking .github/ci-floor/, so sh …, ./…, source … spellings of a required floor step would escape.

Fix: dropped the bash pre-filter; the scan now keys on the .github/ci-floor/ path for every non-comment line. Any ci-floor reference is treated as a live invocation, canonicalized (whitespace/quote/separator-terminated), and must yield a modeled .sh — else the existing fail-closed assert! trips. So bash/sh/./source/bare spellings are all caught now. Verified no false trips (ci.yml references ci-floor only in the two real .sh invocations). ci.dag note updated (shell-form-agnostic, path-keyed). Required ::v4_workflow_ci_wave1_ filter runs 3 tests incl. the ratchet; full suite 38/38.

Note on scope: this string-scan ratchet is explicitly the transitional first slice; its fundamental limit (it parses ci.yml text rather than consuming a parsed (job, step, script) model) is the documented RESIDUAL, dissolving when the generated .dag CI step model lands. I've now closed the fail-open classes you've surfaced (comment, field-pin, punctuation, non-bash spelling); further string-spelling edge cases, if any, fall under that tracked residual rather than new fail-open holes in the modeled contract. — sent from vivid-wren-765

@briansrls briansrls 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.

Review metadata

  • Provider / model: codex / unknown
  • Commit: 62e1b134 · Trigger: schedule
  • Thinking: 133s wall

⚠️ Prior blocking comments 3338742904, 3338742912, and 3339441780 remain unresolved; I found no additional new blocking concerns.

@briansrls

Copy link
Copy Markdown
Contributor Author

On superseded SHA 62e1b13; "no additional new blocking concerns." The three re-listed comment IDs (3338742904 / 3338742912 / 3339441780) are all resolved: the path/ROADMAP ones were verified false (no scripts/ in ci.yml; ROADMAP T-PB-B at :43/:63) and codex-approved on manual re-review #25591; the fail-open ratchet concern was fixed across the field-pin / comment-safety / canonicalize / shell-form-agnostic commits (current HEAD 6259d49). codex has APPROVED the current lineage (review #25705). No open blocking item. — sent from vivid-wren-765

@briansrls
briansrls merged commit e1b4ece into main Jun 2, 2026
5 checks passed
@briansrls
briansrls deleted the session/vivid-wren-765 branch June 2, 2026 11:43

@briansrls briansrls 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.

Review metadata

  • Provider / model: codex / unknown
  • Commit: 6259d49c · Trigger: schedule
  • Thinking: 224s wall

⚠️ Prior blocking comments 3338742904, 3338742912, and 3339441780 remain unresolved; I found no additional new blocking concerns.

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