Skip to content

E09: slice-to-scenario traceability in planning artifacts - #438

Merged
TheAmericanMaker merged 3 commits into
mainfrom
feat/e09-traceability
Sep 22, 2026
Merged

TheAmericanMaker merged 3 commits into
mainfrom
feat/e09-traceability

Conversation

@TheAmericanMaker

Copy link
Copy Markdown
Member

feat: slice-to-scenario traceability in planning artifacts (E09)

The engineering record (E01) refuses a slice that proves no scenario. The
artifacts that feed planning -- both reimplementation specs and the project
plan -- had no such structure: scenarios were a numbered table with no
stable handle, scope tiers were prose, and nothing said which scenario
proved which promise. E04 left that seam open ("deriving a plan from an
existing analysis artifact is deliberately NOT implemented"). This closes it.

Templates: scenarios gain a stable Scenario ID and a Tier; a Slices table
carries Slice ID, deliverable, modules, proved scenario ids, dependencies
and tier, in the record's own vocabulary so a plan lifts without
translation. The language-agnostic spec states obligations as what must be
observed, never as a command; the opinionated variant may carry a Proof
command column because its stack is known. Validation rows and pipeline
completion criteria were changed together in all five pipelines that carry
these phases, and both producing SKILLs now instruct the session, including
the rule that an empty proof list is not a plan.

core/engineering/lift.ts reads those tables into the record vocabulary and
refuses on exactly the grounds buildChangePlan refuses: empty proof list,
unknown or self dependency, unknown scenario, an unowned minimum-viable
scenario, duplicate ids, and a row with content but no id (a silently
dropped row would count ownership against a table the author never saw).
Errors are a complete list rather than a first failure; lifting the
repository's own pre-E09 self-audit specs is what showed an early return was
hiding the second missing structure. The lifter imports nothing and sits in
the pure layer.

Tests: seven pipeline invariants (the carrying pipelines are enumerated, not
assumed), nineteen lifter tests including four that hand the same slices to
E04 and assert the two halves agree, the shipped templates lifting clean,
and a compatibility test against a real shipped self-audit artifact. Fifteen
mutations; fourteen bite. The one survivor (loosening the table-separator
regex) is documented untested-by-construction: it is an equivalent mutant on
every observable, and the tight form exists to make the blank-row branch
reachable, not because the loose one misbehaved.

Dogfood: two modules of the v0.25.0 self-audit spec converted by hand, lifted
and planned clean, then each slice inspected for whether its scenarios prove
its promise. Five of eight do; two make universal promises with instance
proofs. The structure catches proof existence, not proof strength -- that
stays with the reviewer, and the dogfood note is the evidence that step is
load-bearing. Running a real phase end to end with a session filling the new
table is recorded as the unfinished half of the issue's step 5.

Scaffold version follows the release marker, not this PR, per the marker's
own policy; existing workspaces receive the standard refresh warning.

Closes #407.

The engineering record (E01) refuses a slice that proves no scenario. The
artifacts that feed planning -- both reimplementation specs and the project
plan -- had no such structure: scenarios were a numbered table with no
stable handle, scope tiers were prose, and nothing said which scenario
proved which promise. E04 left that seam open ("deriving a plan from an
existing analysis artifact is deliberately NOT implemented"). This closes it.

Templates: scenarios gain a stable Scenario ID and a Tier; a Slices table
carries Slice ID, deliverable, modules, proved scenario ids, dependencies
and tier, in the record's own vocabulary so a plan lifts without
translation. The language-agnostic spec states obligations as what must be
observed, never as a command; the opinionated variant may carry a Proof
command column because its stack is known. Validation rows and pipeline
completion criteria were changed together in all five pipelines that carry
these phases, and both producing SKILLs now instruct the session, including
the rule that an empty proof list is not a plan.

core/engineering/lift.ts reads those tables into the record vocabulary and
refuses on exactly the grounds buildChangePlan refuses: empty proof list,
unknown or self dependency, unknown scenario, an unowned minimum-viable
scenario, duplicate ids, and a row with content but no id (a silently
dropped row would count ownership against a table the author never saw).
Errors are a complete list rather than a first failure; lifting the
repository's own pre-E09 self-audit specs is what showed an early return was
hiding the second missing structure. The lifter imports nothing and sits in
the pure layer.

Tests: seven pipeline invariants (the carrying pipelines are enumerated, not
assumed), nineteen lifter tests including four that hand the same slices to
E04 and assert the two halves agree, the shipped templates lifting clean,
and a compatibility test against a real shipped self-audit artifact. Fifteen
mutations; fourteen bite. The one survivor (loosening the table-separator
regex) is documented untested-by-construction: it is an equivalent mutant on
every observable, and the tight form exists to make the blank-row branch
reachable, not because the loose one misbehaved.

Dogfood: two modules of the v0.25.0 self-audit spec converted by hand, lifted
and planned clean, then each slice inspected for whether its scenarios prove
its promise. Five of eight do; two make universal promises with instance
proofs. The structure catches proof existence, not proof strength -- that
stays with the reviewer, and the dogfood note is the evidence that step is
load-bearing. Running a real phase end to end with a session filling the new
table is recorded as the unfinished half of the issue's step 5.

Scaffold version follows the release marker, not this PR, per the marker's
own policy; existing workspaces receive the standard refresh warning.

Closes #407.
Found while trying to break the agreement claim myself, ahead of review.
buildChangePlan does not check id grammar; only the store does. So a
scenario id like "S 01" lifted clean, planned clean, and would have been
refused three steps later with invalid-local-id, for a reason invisible in
the document. The lifter now applies isLocalId to every scenario and slice
id and names the grammar in the refusal. A new test proves both directions:
five bad ids refused here, and every id the clean fixture uses accepted by
validateRecordOfKind. Both grammar checks bite when removed. 1233/1233.
…(E09)

Adversarial review (deleg_1ebf14c6) broke both headline claims of the
first lifter with live reproductions. Seven real defects; this closes all
of them and replaces the reader rather than patching it.

Rows the author wrote were dropped silently. The reader ended the table
at the first line without a leading pipe, so a GFM-legal row written
without one, or a blank line used to group rows, lost that row and every
row after it with errors: [] -- the exact outcome the commit message said
was prevented. The reader now follows GFM: leading pipe optional, `\|` a
literal, blank lines do not end a table, prose between rows is refused as
interrupted-table, a row whose cell count differs from the header is
refused as ragged-row, the delimiter row is the line after the header and
nothing else, fenced code is invisible, and a heading that appears twice
is refused rather than picked.

"Refuses on exactly the grounds buildChangePlan refuses" was false three
ways: a dependency cycle, an empty deliverable, and an empty scenario
description all lifted clean and E04 refused them. The agreement tests
could not see any of it because the planFromLift helper REPAIRED the
lifted values before E04 saw them (`deliverable || id`, `description ||
"(from artifact)"`, `depends_on: []`). The helper now carries values
verbatim, and the lifter walks dependencies the way planning.ts does.

A misspelled column suppressed every row-level check. Only the id column
gates the row loop now. The "equivalent mutant" claim on the old separator
regex was wrong (`| - |  | - |` distinguished them); that regex is gone.

The shipped templates' blank example rows were themselves refused by E04
for an empty description; they carry parenthesised placeholders now and
the SKILLs say to replace them. The E09 invariants also pin the validation
rows and completion criteria as the same sentences, word for word, on both
sides -- the earlier tests checked each half loosely.

Mutation: 25 operators, 24 bite. The survivor (CRLF normalization in the
fence pass) is documented equivalent: every consumer is anchored or
trimmed, and the CRLF test passes either way.

Confirmed sound by the same review and left alone: no author text is used
as an object key, no ReDoS at 25KB, the language-agnostic spec carries no
proof commands.
@TheAmericanMaker
TheAmericanMaker merged commit a240571 into main Sep 22, 2026
6 checks passed
@TheAmericanMaker
TheAmericanMaker deleted the feat/e09-traceability branch September 22, 2026 16:38
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.

[E09] Add slice-to-scenario traceability to planning artifacts

1 participant