Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 20 additions & 12 deletions .add/milestones/affordance-truth.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
---
type: Milestone
title: The engine's affordances name the beat you are actually on
status: direction
status: done
generated: { by: add/3.2.0, at: 2026-08-17 }
verified: []
verified:
- { by: "Tin Dang", at: 2026-09-01, act: check, authority: process, via: process, boxes: "EXIT:1,2,3,4,5,6,7" }
---
## CARD
goal: Make every `next:` the engine prints name a verb that can actually succeed against the node it names, so a node that was created and never authored is visible as such instead of reading identical to one that is ready for approval.
Expand Down Expand Up @@ -80,21 +81,28 @@ risks:
fails at publish, late.

## EXIT
- [ ] A Task or Milestone that still carries template placeholders is never advised to `freeze` — every
surface that derives a `next:` for it names authoring instead, proven by a test per surface and not
by reading the diff (← authoring-beat-named)
- [ ] The advice-time predicate is the SAME one the refusals use, so a node the engine advises to freeze
- [x] A Task or Milestone that still carries template placeholders is never advised to `freeze` by any
surface that CAN read its body — `new`, `todo`, the CARD scaffold and `freeze` itself — proven by a
test per surface and not by reading the diff. `status` derives the same beat from T0 signals alone,
because `build-orient`'s frozen R:T2SCAN forbids it reading a body; the one shape that escapes it
(authored `gives:`, template RULES) is recorded in `_is_scaffold`'s docstring and caught by `todo`
and `freeze`. AMENDED 2026-09-01: the original wording said "every surface", which no surface bound
by R:T2SCAN can satisfy (← authoring-beat-named)
- [x] The advice-time predicate is the SAME one the refusals use, so a node the engine advises to freeze
is a node `freeze` accepts — no third notion of "authored" enters the engine (← authoring-beat-named)
- [ ] `test_new_scaffold.py`'s pinned affordance string is re-aimed at the corrected verb rather than
- [x] `test_new_scaffold.py`'s pinned affordance string is re-aimed at the corrected verb rather than
dropped, so the scaffold's `next:` stays a pinned interface (← authoring-beat-named)
- [ ] `freeze` refuses a Milestone whose CARD, SCOPE, GROUND or EXIT are still template, proven by a
check that is red against today's engine — which records the stamp (← authoring-beat-named)
- [ ] All four engine twins carry the change and the MD5 pins are re-aimed; both test roots green
- [x] `freeze` refuses a Milestone whose CARD `goal:`, CARD `why:` or `## EXIT` criteria are still
template, proven by a check that is red against today's engine — which records the stamp. AMENDED
2026-09-01: narrowed from CARD · SCOPE · GROUND · EXIT to the three the milestone lifecycle
actually reads, since `milestone_done` refuses on `why:` and on the EXIT tally, and a guard
reaching SCOPE and GROUND would refuse real milestones whose ground is thin (← authoring-beat-named)
- [x] All four engine twins carry the change and the MD5 pins are re-aimed; both test roots green
(← authoring-beat-named)
- [ ] Every skill-tree sentence claiming a command shows or prints something is proven by DRIVING that
- [x] Every skill-tree sentence claiming a command shows or prints something is proven by DRIVING that
command and reading its stdout — a string found in `add.py` satisfies nothing, since that is
precisely what let `goal not met (m/n exit criteria)` survive (← claimed-output-guard)
- [ ] The two false `loop.md` claims are repaired in all three live skill trees, and the guard is shown
- [x] The two false `loop.md` claims are repaired in all three live skill trees, and the guard is shown
RED against the unrepaired tree first — a guard that never refused is not evidence
(← claimed-output-guard)

Expand Down
1 change: 1 addition & 0 deletions .add/runs/authoring-beat-named-r1.xml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions .add/runs/authoring-beat-named-r2.xml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions .add/runs/authoring-beat-named-r3.xml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions .add/runs/claimed-output-guard-r1.xml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions .add/runs/claimed-output-guard-r2.xml

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions .add/specs/method.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ how work proceeds, and what a gate costs

## Deltas
- <what changed, and the evidence that changed it>
- [ADD · open] A node authored before a merge goes STALE and must be re-measured before it is frozen: nine add.py line anchors had drifted, a check pinned a verb count that had changed, and a milestone criterion described a guard scope the maintainer had since narrowed. Trust a nodes prose about the engine only after driving the engine. (evidence: /tasks/authoring-beat-named.md)
- [ADD · open] An unrecognised sensitivity value silently degrades the authority floor instead of refusing: SENSITIVITY_FLOOR maps mechanical|data|architecture|security, and .get(sens, "process") turns any other word into the LOWEST floor. Two nodes declared sensitivity: high and gated at process where they meant plan. Same class as the rest of this branch — an unknown reads as clean. (evidence: authority_for add.py:1293 · .add/tasks/authoring-beat-named.md)
- [ADD · open] A guard's INPUT PARSER is part of the guard: `_changed_paths` read git's porcelain -z stream as if every record carried a status prefix and every path were repo-parent-relative, so the sensitive-path refusal fired on paths that did not exist and missed the file actually edited. A refusal is only as true as the stream it reads. (evidence: tests/engine/test_premerge_review_fixes.py)
- [ADD · open] A guard that fires on a malformed thing and never on a missing one is a guard you get past by DELETING, not by forging — an absent section reads as clean to every consumer. Check for the ABSENCE of what is required. (evidence: /tasks/sealed-gate-enforcement.md gate PASS · runs/2.md)
- [ADD · open] The gate binds covers: referents by BARE test id, so a guard name defined in two files (test_guard_messages_name_their_target) binds to neither. Name a guard after its subject. (evidence: /tasks/box-check-verb.d/runs/2.md)
Expand Down
1 change: 1 addition & 0 deletions .add/specs/quality.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ what counts as proof

## Deltas
- <what changed, and the evidence that changed it>
- [TDD · open] The gate binds covers: referents by BARE test id, so a PARAMETRIZED check binds NOTHING — pytest reports it as test_x[param]. A green parametrized check can leave its rule unbound while reading as covered. A module name (test_tree_parity) binds nothing either; cite the real test function names. (evidence: /tasks/claimed-output-guard.md gate)
- [TDD · open] A gate that cannot READ its input must refuse, never tally zero. Teaching the goal-gate to skip fenced blocks meant an unclosed fence emptied the tally, and `total == 0` takes the 'no exit criteria' branch — which CLOSES the milestone with unmet criteria in the file. (evidence: tests/engine/test_premerge_review_fixes.py)
- [TDD · open] Never take a timestamp from the clock to compare against a filesystem. Flooring the clock to the second fixed the coarse-filesystem false-stale but blunted the check; a sentinel written on the SAME filesystem fixes it without losing any discrimination the filesystem offers. (evidence: tests/engine/test_premerge_review_fixes.py)
- [TDD · open] Every capability a doc PROMISES is a test nobody wrote: the sentence "a box the AI ticked never reads as a human's" was false for two minor versions because no check bound prose to behaviour. (evidence: /tasks/sealed-gate-enforcement.md M6 · runs/2.md)
Expand Down
Loading