fix: resolve the zero-Unit code-generation location in the traceability sensor - #1179
Merged
leandrodamascena merged 2 commits intoSep 15, 2026
Conversation
…ty sensor A zero-Unit directive writes code-generation artifacts under construction/code-generation/ with no Unit segment, as the stage prose requires. The traceability sensor derived the Unit from a three-segment path only, so that two-segment location yielded no Unit, the resolver refused with "cannot derive the construction unit", and every zero-Unit scope recorded SENSOR_FAILED at code generation regardless of coverage. Recognise the stage-level location for code-generation and resolve an empty-Unit context for it. A single constructionDir() helper maps a Unit, or its absence, to the record directory, so the NFR requirements and rules.md reads pick up the stage-level equivalents; the story-map join runs only when a Unit exists. Other per-Unit stages are unchanged. t281 adds the zero-Unit case: complete coverage passes, and a file that omits a stage-level BR id is refused through missing_from_upstream_ids. Closes awslabs#1011
leandrodamascena
approved these changes
Sep 15, 2026
leandrodamascena
left a comment
Contributor
There was a problem hiding this comment.
Thanks for the focused fix.
I reviewed the current head de9756eb against main at a517a061. The change aligns with #1011 and restores the existing zero-Unit traceability contract.
During review, I found that a stage-level path was also accepted when a Unit DAG existed. I pushed de9756eb to require the DAG to be absent and added regression coverage.
Validation passed: 15 traceability tests, typecheck, lint, coverage registry, packaging determinism across seven harnesses, and integration on the current main.
Non-blocking follow-up: #1176 conflicts in the same code block. The combined result passes all 16 traceability tests after retaining both changes.
5 tasks
wowzoo
pushed a commit
to wowzoo/aidlc-workflows
that referenced
this pull request
Sep 15, 2026
…ranch Clean: 0 conflicts. `awslabs#1179` touches `core/tools/aidlc-sensor-traceability.ts` and its suite, neither of which this branch had edited. Checked for the semantic collision a textual merge cannot report, since the last two absorptions each hid one: the shipped rosters and product-name assertions still read this row's own wording, and the `kiro-ide -> kiro` resolution added in the review round is intact. `tests/unit/t281-*.test.ts` carries two files sharing the id — the MCP registry one and the traceability one. Both are present upstream and at the merge base, so that collision is not this branch's and is left alone. Gates: install, package, typecheck, lint and `package.ts --check` rc=0, the last deterministic across all six rows. t281 (both) + t332 + t298 55/0.
apackeer
added a commit
that referenced
this pull request
Sep 17, 2026
* origin/main: fix: make compiled dispatch exhaustive over TOOLS so native review briefs route (#1070) (#1115) test: skip POSIX gate-sensor fixture on Windows (#1208) fix: make /aidlc compose scopes durable across an engine reinstall (#1159) fix: refuse orphaned positionals at intent-create instead of storing a truncated description (#1114) (#1195) fix: route compiled gate-sensor dispatch through the engine namespace (#1166) fix: name the accepted values in review-path refusals (#1082) (#1194) fix: discover stage-level summary questions when units are skipped (#1110) fix: keep a JSON-scalar gate reply instead of parsing it away (#1186) fix: resolve the zero-Unit code-generation location in the traceability sensor (#1179) fix(config): one quiet line for --show, and honest source options on a copy-channel refresh (#1185) test(t238): normalize walkFiles separators in the invocation-surface selector (#1184) fix(config): Kiro provides its own model access, so the provider section has nothing to ask (#1183) chore: prepare 2.9.0 release (#1181) feat!: classic scope v1 parity with scope-owned ceremony switches (#1151) fix: publish changed previews without a daily cap (#1178) fix: separate Bun copy and native installer runtimes (#1174) fix: publish next-patch previews nightly (#1169) fix: keep review bookkeeping out of the artifact, and out of the reviewer's findings (#1160) fix: measure the review budget against the engine's own ordinal, not the caller's (#1158)
apackeer
added a commit
that referenced
this pull request
Sep 17, 2026
Rebase fix-ups onto main after #1151, #1160 and #1179 moved the intent record's engine state under .aidlc-engine/ and folded the change-control verb into config-change: - read the active-directive marker, review records and guard-refusal records from their .aidlc-engine/ paths - select relaxed Change Control with `config-change --change-control` - force the three recordable bypasses #1151 added (sensors, learnings, summary confirmation) to 0 under the production guard profile - regenerate the coverage registry and ratchet from the merged tree
scotb
pushed a commit
to scotb/aidlc-workflows
that referenced
this pull request
Sep 18, 2026
) * fix: make guard recovery executable across workflow states * test: repair guard recovery CI fixtures and contract checks * test: adapt guard recovery fixtures to the post-2.9.0 engine layout Rebase fix-ups onto main after awslabs#1151, awslabs#1160 and awslabs#1179 moved the intent record's engine state under .aidlc-engine/ and folded the change-control verb into config-change: - read the active-directive marker, review records and guard-refusal records from their .aidlc-engine/ paths - select relaxed Change Control with `config-change --change-control` - force the three recordable bypasses awslabs#1151 added (sensors, learnings, summary confirmation) to 0 under the production guard profile - regenerate the coverage registry and ratchet from the merged tree * docs: render the recovery orchestrator route per install channel awslabs#1174 separated the Bun copy runtime from the native installer runtime and guards their invocation surfaces: copy-channel skills may not mention the literal `aidlc engine` command. The guard-recovery execution paragraph named both spellings verbatim; use the {{INVOKE}} token so each channel renders its own orchestrator route. * fix: render a tree-path harness dir by its project-relative leaf The AIDLC_HARNESS_DIR seam may name an installed tree by absolute path (t337 from awslabs#1151 does). renderGuardOperation rejected anything but a bare dot-directory and threw from inside evaluateGuardRefusal, turning a summary refusal into a crash. An absolute value now contributes its leaf directory; relative spellings must still be that bare leaf. * test: keep the AIDLC_HARNESS_DIR seam a leaf name in t337 Restores renderGuardOperation's strict dot-directory contract. harnessDir() is a project-relative leaf by contract (deriveHarnessDir validates it), and t337 already pins the scope grid, stage graph and scopes directory by absolute path, so its absolute AIDLC_HARNESS_DIR was the off-contract input. Rendering an absolute tree by its leaf (288ffb9) hid the misuse and produced a command that a project without a local harness copy cannot run. * fix: let a later human response supersede a recorded restart selection A consumed command/external-work selection stayed `ready` on the ask marker after any later human prompt, so the Plan Approval hook kept admitting the returned native reset for an unchanged state even after the human had said not to. consumeSharedDirectiveAsk now re-resolves a different later response as a fresh selection (an identical re-record is idempotent); an unmatched answer records no feedback and the next response can select again. Human-input feedback handling is unchanged. Covered by the real hook in t265b and the marker contract test; documented in the state-machine reference. * test: skip the runner-marker assertion outside the runner The profile marker exists only under tests/run-tests.ts; a direct `bun test tests/unit/t-runner-production-guards.test.ts`, which docs/reference/09-testing.md documents, failed on it. * feat: park a discarded Bolt attempt so an abort is recoverable `aidlc-worktree discard` (the owner behind `bolt abort --discard`) removed the worktree, deleted `bolt-<slug>` and its reflog, and dropped the retained reviewed-source refs: uncommitted work was gone and unmerged commits were unreferenced. Before the audit row it now snapshots the working tree (tracked and untracked, not ignored) with a temporary index and `commit-tree`, parks the head under `refs/aidlc/parked/<slug>/<stamp>/head`, and relocates the reviewed-source refs beside it; only then does it emit `WORKTREE_DISCARDED` (with `Parked ref`/`Parked commit`) and tear down. A parking failure refuses before anything is destroyed. New `worktree restore --slug <slug> [--parked <stamp>]` checks the newest parked head out under `.aidlc/restored/bolt-<slug>-<stamp>` on `restore/bolt-<slug>-<stamp>` — a namespace no list, doctor, evidence scan or `create` collision check looks at, so the recovery continuation that recreates the same slug still succeeds and both attempts survive. `worktree purge` removes parked refs explicitly and refuses while a restore checkout exists. `bolt abort` forwards `parked_ref`; the recovery remedy names the restore command. The abort argv and the Plan Approval hook are unchanged. * docs: record the abort admission trade beside the hook The exact native abort is admitted on conductor-obtained consent; the hook does not authenticate it. With discard parking the attempt, a mistaken abort is recoverable, and a mechanical selection receipt stays a later candidate. * docs: keep the pinned discard-before-prepare wording; note parking in a following sentence t305 asserts the exact recovery sentences in the construction and recovery protocol modules. Discard still discards, so the original wording stands; the restorability note follows as its own sentence. * fix: park raw bytes under clean filters so a discarded attempt restores exactly `git add -A` runs configured clean filters, so the parked blob of a dirty filtered file could differ from the bytes `worktree remove --force` was about to destroy. Rebind raw worktree bytes for every filtered regular path the way reviewed-source binding already does (filteredRawIndexEntries + hash-object --no-filters + update-index --cacheinfo); symlinks and gitlinks stay as staged. A snapshot that cannot be compared refuses before teardown. Regression: a lossy clean filter no longer alters parked or restored bytes; a broken required filter refuses without destroying the live checkout. * fix(ci): drop persisted checkout credentials from the production-guards job; keep the source orchestrator on its own process identity The new `test_guards` job runs PR-controlled tests and uploads their logs, so its checkout no longer persists the token. `spawnState` had moved from process-identity gating to `aidlcEngineCommand`, which prefers a project-set AIDLC_COMPILED_EXECUTABLE even in a source process; the orchestrator now passes its own identity, while adapters keep receiving the executable through the environment as before. * fix: infer the parked repository for restore/purge; spawn the state child by process identity only `restore --slug` and `purge --slug` now locate the repository holding `refs/aidlc/parked/<slug>/` among the same candidates discard consults (project root, sibling repos, audit-recorded repos), so the documented selector-free command works in a multi-repo intent; several matches ask for --repo, none reports no parked attempt. The compiled orchestrator spawns its state child with its own process.execPath, never an executable supplied through the environment. --------- Co-authored-by: Leandro Damascena <lcdama@amazon.pt>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
For a zero-Unit directive (no Unit DAG:
poc,bugfix,refactor,security-patch,express) thecode-generationstage writes its artifacts under<record>/construction/code-generation/"with no synthetic Unit segment" (stage prose, Step 1). Thetraceabilitysensor'sextractUnitName()derives the Unit from a three-segment path (construction/<unit>/<stage>/traceability.json), so the two-segment zero-Unit path yieldsnull,resolveUnitContext()returns "cannot derive the construction unit from output path", and the sensor recordsSENSOR_FAILEDon every zero-Unit code-generation run no matter what the artifact contains.Closes #1011.
Changes
core/tools/aidlc-sensor-traceability.tsisZeroUnitOutput()recognises the stage-levelconstruction/code-generation/traceability.jsonlocation;resolveUnitContext()returns an empty-Unit context for it instead of a refusal. Restricted tocode-generation, the only stage that runs without a Unit today; every other per-Unit stage keeps deriving a Unit exactly as before.constructionDir()is the one place that maps a (possibly empty) Unit to its record directory:construction/<unit>/<stage>/per Unit,construction/<stage>/for the zero-Unit run. The code-generation branch reads NFR requirements andrules.mdthrough it, so a zero-Unit run picks up the stage-level equivalents.stories.mdis upstream, matching the stage-level scope.unit "".tests/unit/t281-sensor-traceability.test.ts- new case "code-generation resolves the zero-Unit stage-level location": requirements plus stage-levelconstruction/functional-design/rules.md, aconstruction/code-generation/traceability.jsoncoveringFR1,NFR1,BR1.1with an existing target file passes; a file that omitsBR1.1is refused throughmissing_from_upstream_ids, which proves the stage-level rules file was resolved.This is deliberately confined to the sensor's path resolution so it rebases cleanly onto #1005 (which moves per-Unit artifacts to
construction/units/<unit>/and states that zero-Unit fallbacks stay stage-level):constructionDir()is the single line to update there. No version bump, badge, or CHANGELOG entry, per the Release Metadata Policy inAGENTS.md.User experience
Before: every zero-Unit workflow recorded
SENSOR_FAILEDfortraceabilityat code generation with "cannot derive the construction unit from output path", regardless of coverage.After: the sensor evaluates the zero-Unit artifact against the stage-level upstream set and passes on complete coverage; per-Unit runs are unchanged.
Checklist
Test plan
On
572c8265(main):The new case fails without the sensor change:
git stash push -- core/ && bun test tests/unit/t281-sensor-traceability.test.tsreports 1 failure ("cannot derive the construction unit from output path").Independent of #1176 (same file, different branch of
resolveUpstream); whichever merges second rebases trivially.Acknowledgment
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of the project license.