Skip to content

feat(84): the survivors-sweep gate — published vocabularies, sweep receipts, sibling pins - #330

Open
gtrabanco wants to merge 23 commits into
mainfrom
feature/84-published-vocabulary-sweep-gate
Open

gtrabanco wants to merge 23 commits into
mainfrom
feature/84-published-vocabulary-sweep-gate

Conversation

@gtrabanco

Copy link
Copy Markdown
Owner

What

The fold survivors rule becomes bytes. Two prose prescriptions already shipped (fold-findings 1.9.0, execute-phase 6.1.0: "change + dependents, survivors swept in the same batch"); nothing enforced them, so a fold ended green while a sibling surface still carried the stale token. This unit turns that rule into three machines and one inventory.

The four scope items

  • S1 — published-vocabulary pin (the F40 class). packages/agentic-workflow-schema/src/vocabularies.ts is the one canonical home: FUTURE_STATUS_KINDS (the open | planned | discarded <YYYY-MM-DD> set no parser read), FINDINGS_TABLE_SEVERITIES, LOG_KIND_TOKENS, SWEEP_CLAIM_KINDS / SWEEP_MISMATCH_REASONS. scripts/vocabulary-parity.test.mjs pins every second copy; scripts/vocabulary-probe.mjs applies the sets across open unit docs and fails closed naming file:line and the offending token. Schema 4.9.0.
  • S2 — sweep-receipt claim kind (the F35/F37/F38/F39 class). scripts/promise-coherence.mjs gains one closed claim kind: a fold appends swept: /<pattern>/<flags> → expected <n> in <glob> to its own log entry, and the gate re-runs each declared grep fence-aware, failing closed with sweep-mismatch and naming file:line, the regex and the observed count. The declaring doc stays in the corpus — the true F35 shape is a stale copy in a sibling section of the same doc. FOLDING.md, fold-findings 1.10.0 and review-code 1.3.0 gain the box that emits and reports it.
  • S3 — negative-capability pins (the F39 class). scripts/structural-sibling-pins.mjs: pin A refuses an inline ## -anchored search outside an allowlisted fence-aware reader (each allowlist entry carries its reason, and the suite proves the allowlist is not vacuous); pin B refuses a carrier-cell echo path that bypasses the one flatten class. Both went RED on four live siblings, all refactored onto sectionBounds, and the shared reader itself never advanced past a scanned line (quadratic on a 50k-char log line) — fixed.
  • S4 — inventory backfill. Dated census recorded as the normative-surfaces@1 rows; no historical unit doc rewritten (closed units stay out of the probe corpus, decision D3).

Verification

Suite Result
node --test scripts/*.test.mjs 951 pass / 0 fail
cd packages/agentic-workflow-schema && bun run test 721 pass / 0 fail
cd packages/agentic-workflow && bun run test 254 pass / 0 fail
bun scripts/check-skill-context.mjs / --routes PASS 28 skills / PASS 14 routes
bun scripts/phase-lint.mjs <unit doc> PASS 7/7 phases
bun scripts/promise-coherence.mjs <unit doc> PASS
bun scripts/version-parity-gate.mjs --content --base main PASS (0.35.2 → 0.36.0)

The one root failure the final sweep caught was review-loop-discipline's maintained fold-findings version pin; it was re-pointed 1.9.2 → 1.10.0 exactly as its own comment orders ("the assertion is re-pointed, never weakened"). No test was deleted or loosened.

Binary compatibility: every previously published schema const is byte-identical (additive only).

Closes #315


Automated writed using a AI

…315

Unit doc in spec-by-reference shape (S1-S4 quoted from the issue, owner ACs
verbatim), provenance receipt, decisions D1-D3 (fenced-quote-only allowlist,
schema consts canonical, probe corpus = open units + fixtures), planning
evidence + obligations ledgers, triage pasted, roadmap row 84 -> defined.
…d sibling pins — RED

Fixtures: F40 reproducer (kept deferred token) + clean unit doc under
scripts/fixtures/vocabulary-probe/; F35 sweep fixtures (seeded stale survivor,
fenced-quote-only clean tree, unparseable declaration). New suites:
vocabulary-probe (5), vocabulary-parity (6), structural-sibling-pins (6),
plus three sweep cases and the conscious closed-set extension in
promise-coherence.test.mjs. All new checks fail at this commit by design.
src/vocabularies.ts: FUTURE_STATUS_KINDS, FINDINGS_TABLE_SEVERITIES,
LOG_KIND_TOKENS, SWEEP_CLAIM_KINDS, SWEEP_MISMATCH_REASONS; index.ts re-exports
with types. The findings-table class set stays canonically
PRE_EXECUTION_FINDING_CLASSES (no second const). Version bump 4.8.0 -> 4.9.0
with the CHANGELOG companion row and the two release-contract version pins
moved in the same PR (the conscious bump path those pins exist to force).
Mirror rule (issue #315 AC5) satisfied: types + version bump, same PR.
…nonical sets

Applies FUTURE_STATUS_KINDS / FINDINGS_TABLE_SEVERITIES /
PRE_EXECUTION_FINDING_CLASSES across the in-flight unit docs' ## Future and
## Findings rows, fence-aware, fail-closed naming file:line + token. Corpus =
open units + fixtures (decision D3): closed units are append-only evidence,
so 79's recorded F40 debt stays out. --root makes the fixture tree a first
corpus. 5/5 probe cases green; live head PASS.
promise-coherence gains the closed 'sweep' kind + 'sweep-mismatch' reason: a
fold's 'swept: /<pattern>/<flags> → expected <n> in <glob>' declaration in its
## Log (or legacy ## Progress log) is re-run as a fence-aware grep — fenced
quotes and the declaring doc's own log sections are exempt (D1), the bounded
glob scope is required (cost bound), and a count mismatch fails closed naming
the declaration file:line, the regex and the observed count, first survivor
included. Differential: the default run's block is byte-identical to the base
tree's (24 checked · 19 skipped, verdict PASS). Suite 27/27.
…age (S3)

Two pattern-level pins in the owning suite, each with a corpus case that
reintroduces the F37/F38/F39 defect it guards:

- pin A refuses any inline `## `-heading search outside the shared
  fence-aware reader (allowlist entries each carry their reason, and the
  suite asserts the allowlist is not vacuous).
- pin B refuses an echo path that emits a carrier cell without the one
  flatten class.

The migrations the pins demanded land here too: unit-lineage, unit-route
and vocabulary-probe delegate to `unit-doc-phases.sectionBounds` instead of
their own fence-blind copies, the sensor's TASKS.md phase reader walks
fences, and `sectionBounds` advances past a scanned line (the loop
re-sliced the same line once per character — quadratic on a 50k-char log
line).
…they caught (S3)

structural-sibling-pins.mjs: pin A refuses any inline /^## -anchored regex
outside the allowlisted fence-aware readers (each entry carries its reason;
fixture reintroduction fails naming file:line); pin B refuses a template push
emitting a raw carrier cell without flattenCell()/bounded(). The pins went RED
on four live F39 siblings, all refactored onto the shared reader: unit-route
sectionBody, unit-lineage sectionBody, workflow-status readPhaseProgress
(fence-aware phase walk), promise-coherence measureSection, plus the probe's
own sectionLines. Bonus find: sectionBounds never advanced past a line once a
section started — quadratic on long lines (2.2s on a 50k-char log line, the
F7 class inside the shared reader itself); loop advance fixed, fingerprint
byte-identical. Sweep gate fix: the declaring doc's Log exemption no longer
leaks onto survivor files, and the declaring doc itself stays in the corpus
(the true F35 shape — stale copy in a sibling section of the same doc — is a
fixture now). Root suite 951/951.
The folded content ships: the Pi package version and its companion row move
together (skills/** trigger set), the README's fold-findings cell names the
declaration, and the eight execute-phase:* routes are re-based for the
FOLDING.md growth with the reason declared per route — estimate and line
ceilings at ceil(measured x 1.10).
… version pin

P6 caught one root-suite failure: review-loop-discipline's maintained
`fold-findings` version pin still read 1.9.2. Its own comment orders the pin
re-pointed on every bump, never weakened, so it moves to 1.10.0 with the
reason appended to the chain.

Every declared suite is green at this head: root 951/951, schema 721/721,
runner 254/254, context and route budgets PASS, phase-lint PASS,
promise-coherence PASS.
The unit doc's References carries the PR URL and the roadmap row 84 settles to
`done · [#330]` through the crate's writer, its dependsOn and description
cells re-emitted unchanged — `bun scripts/roadmap-settle.mjs` exits 0 with 111
unit docs checked and 0 violations.
…, not the roadmap row

The head test asserted documentsChecked >= 1, gating the root suite on the
release step's own roadmap write (row 84 settles to done once the PR exists)
and turning a legitimately empty corpus into a red gate. The pin is now the
corpus rule itself: the scanned set must equal the set re-derived from the
roadmap and fix index, and the non-vacuity witness moves to the frozen
fixture corpus, which asserts its exact two documents.

Surfaces swept: the head test's count assumption, and the probe now reports
the documents it scanned (the field the pin reads).
…acks through the shared reader

Three defects in the probe's document-reading internals, one rollback
boundary: outsideFences() was dead code while the Future and Findings loops
each re-implemented the same fence walk inline (the F37-class duplication the
unit's own S3 pin exists to kill), and every in-flight doc was read twice per
run — once to filter, once to scan. inFlightDocs now returns {file, lines}
pairs consumed directly, and one unfenced() helper built on the exported
openFence/closesFence owns the walk for both sections.

The clean fixture gains a fenced F40 quote so the shared path is proven to
exempt the fold's own evidence; the fixture corpus assertion names its exact
two documents. Surfaces swept: the dead helper and its inline copies.
…ne unit, and inside a named class

Four defects in one file's claim-execution paths, one validator set
(`node --test scripts/promise-coherence.test.mjs`), one rollback boundary:

- F2 (security): a sweep declaration's pattern body was compiled with
  `new RegExp` and no bound, then run per line over up to 5000 files x 2 MB.
  `sweepPatternRefusal` now bounds the body (<= 200 chars) and refuses a
  quantified group whose own body is quantified — the reviewed reproducer
  `(a+)+$` cost 83 s for five tests on one 29-character line. An outside-bound
  declaration is refused before it is compiled and the claim names which bound
  tripped; the reason vocabulary is unchanged (`sweep-mismatch`), so no published
  set moved.
- F3 (code): `sweepCount` walked the file with `Buffer.byteLength` offsets while
  the declaring document's Log exemption comes from `sectionBounds`, a string-index
  range — the two units diverged on every doc carrying non-ASCII before `## Log`,
  and a clean fold failed its own declaration. The scan now walks string indices,
  and the comments that called the ranges byte ranges are corrected.
- F7 (code): the 5000-file ceiling was checked after `push` and `return`ed only out
  of the current recursion level, so sibling directories appended past the bound.
  `sweepFiles(root, glob, maxFiles)` checks at every level top and stops; the
  ceiling is injectable so the bound is proven without 5000 files.
- F12 (verify): every `(validator: …)` cell of a unit doc named a form the reader
  allowlist refused, so the gate printed `verdict PASS` over `0 checked · 7 skipped`.
  The committed report validators are now re-run argv-style (no shell, no glob, no
  placeholder, never a `.test.mjs`, never this gate itself), the span search prefers
  a runnable command instead of binding the cell's first prose span, each refusal
  names itself, and a document that machine-checked nothing says so in its tally.

Prose moved with the bytes, per this unit's own survivors rule: `sweep-declaration@1`
is declared as a column-zero grammar block in `FOLDING.md` (the id the schema const
already cited and `AGENTS.md` now lists), `fold-findings` states the bounds, and
`LEDGERS.md` names the class the gate re-runs. execute-phase 6.5.0, fold-findings
1.11.0, pre-execution-review 2.8.3; the fold-findings version pin is re-pointed;
the execute-phase route ceilings are re-based on the measured route with the
growth source named.

Not folded by this batch: the zero-checked PASS is disclosed, not refused — making
it a hard fail would redden every plan-time unit doc whose validators are suite
forms, which is a contract change for the gate's owning reference, not a repair here.
…e path

HEADING_READER_ALLOWLIST was keyed by base name and matched with
path.basename(hit.file), so any script in any subdirectory that happened to
share an allowlisted name (a nested unit-doc-phases.mjs) bypassed pin A in
silence. Hits now carry repoFile (the path relative to this checkout) and the
filter compares whole paths, so an exemption belongs to one file, not to a name.

The non-vacuity pin gets stronger with it: every allowlisted key must still carry
a heading search or the entry fails the suite as prunable, instead of the old
'some entry is still used' test. A new corpus case reintroduces the pattern under
an allowlisted name in a nested directory and requires the violation.
Nine OPEN rows leave `## Findings` and become `## Log` F lines naming the fold
commit that repaired each one, each carrying the swept declarations this unit
prescribes for a token- or claim-shaped change — the survivors rule applied to
its own repairs, so the gate re-runs the folds' survivor greps rather than
trusting the prose. G2 records the gate runs at the fold head; E14 records
promise-coherence over this document, where every declaration reproduced and
the tally reads 13 checked against the 0 checked that opened the cycle.

`## Next` states the real next action: the bounded cycle-2 re-review of the fold
diff, then the merge gate. F9-F11 remain report-only notes and F13 the batched
proposal — no ledger row, no backlog (D3).

Surfaces swept: the empty findings table, the Next section's stale claim that the
end review was still to come, and the fold commits' citations in the log.
The --pins gate requires an exact pin to equal the local sibling version,
because the merge publishes that version and a consumer cannot reach a
package the pin does not name. The pin still said 4.8.0 while
packages/agentic-workflow-schema declares 4.9.0.
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.

NEW FEATURE: published-vocabulary machine pin + fold survivors-sweep gate — make the survivors rule executable

1 participant