Skip to content

[AAASM-5750] 📝 (types): Point the §6 Planned referent at the capability ticket - #364

Merged
Chisanan232 merged 4 commits into
mainfrom
v0.0.1/AAASM-5750/docs/planned_referent
Aug 13, 2026
Merged

[AAASM-5750] 📝 (types): Point the §6 Planned referent at the capability ticket#364
Chisanan232 merged 4 commits into
mainfrom
v0.0.1/AAASM-5750/docs/planned_referent

Conversation

@Chisanan232

@Chisanan232 Chisanan232 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Target

  • Task summary:

    Repoints the two ADR 0033 §6 Planned referent sites from AAASM-5681 to AAASM-5750, and adds a source scan that keeps them pointed correctly.

    §6 scopes Planned to "decided but not implemented — a ticket reference; no capability claim." AAASM-5681 measured the absence of an SDK-side audit sink; it never intended to build one. Unlike go-sdk and python-sdk, node is not broken yet — AAASM-5681 is still open, so the reference still resolves to live work. It breaks the moment 5681 closes, which is why it is corrected now rather than after.

    This is AAASM-5750's own "Until then" step. The capability itself — actually wiring a sink — stays open.

  • Task tickets:

    • Task ID: AAASM-5750.
    • Relative task IDs:
      • AAASM-5755 — filed from this work; see "Found while doing this" below.
      • AAASM-5681 — the ticket being repointed away from.
    • Relative PRs:
      • ai-agent-assembly/go-sdk#199 and ai-agent-assembly/python-sdk#316 — the same change in the sibling SDKs. Independent; no merge ordering required.
  • Key point change:

    Sites repointed (2)

    file:line text
    src/types/gateway-governance.ts:23 ADR 0033 §6: recording here is **Planned** (…), not *Observed*.
    src/wrappers/with-assembly.ts:166 Supplying a sink that retains it is tracked as …

    The second carries no §6 term but is the same kind of forward reference — a pointer to the remedy — so it goes stale the same way.

    Deliberately NOT repointed. Stated so the boundary is reviewable. Each cites AAASM-5681 as the ticket that measured the drop, which is still true:

    • src/gateway/client.ts:23,50,183, src/core/init-assembly.ts:92,104,123,140,837, src/types/assembly-context.ts:89, src/types/gateway-governance.ts:3
    • tests/audit-sink-disposition.test.ts headers, tests/quickstart-negative-control.test.ts:268
    • README.md and docs/** prose
    • the runtime warning string emitted by initAssembly, and the test constant asserting it

    The gate. Nothing tests a comment — it is the one artifact in a source file with no mechanical check on it. tests/planned-referent.test.ts walks the repo, pairs each §6 Planned with a ticket reference on the same line, and asserts the referent. Two controls, both run:

    control result
    revert gateway-governance.ts:23 to AAASM-5681 FAIL, naming that site
    break the scanned-suffix set so the walk reaches no files FAIL on the floor: scan found 0 …, floor is 1 … passing over nothing

    The second matters as much as the first: an empty scan and a clean tree otherwise report the same result.

    Found while doing this — filed, not fixed here. node-sdk describes one state with two conflicting §6 terms:

    file:line term
    src/types/gateway-governance.ts:23 Planned
    src/wrappers/with-assembly.ts:165 Unmeasured
    tests/quickstart-negative-control.test.ts:268 Unmeasured

    go-sdk (tool_wrapper.go:111-116) and python-sdk (core/audit_sink.py:24-26) both reason this out explicitly and reach the opposite conclusion: §6 reserves Unmeasured for an action nothing inspected, where nothing is known — and here exactly where the record stops has been measured, by this repo's own audit-sink-disposition.test.ts. That is a claim change, not a referent change, so it is AAASM-5755 rather than scope creep in this PR.

    Consequence for the gate, recorded in its header rather than left to be discovered: the scan keys on the §6 term, so today it reaches one of those three sites. When 5755 lands and the term is applied uniformly, the scan covers all three with no change to the scan. src/types/assembly-context.ts:18,33,36 also says Unmeasured, about a different subject (whether a call is evaluated or blocked at all) — not disputed, and must not be swept.

Effecting Scope

  • Action Types:
    • ✏️ Modifying existing something
      • 🟢 No breaking change
  • Scopes:
    • 🫀 Data model and types
    • 🧪 Testing
      • 🧪 Unit testing

Test Result

gate result
pnpm test 665 passed, 2 skipped (72 files passed, 1 skipped)
pnpm typecheck exit 0
pnpm lint exit 0
prettier --check on changed files clean
vitest run tests/planned-referent.test.ts 2 passed, both controls exercised

Comment-only change plus one new test file; no runtime behaviour changes.


Review round 2 — the gate was broken, and it was broken the way it was built to prevent

Independent review found three ways the first gate could not fail. All three had one cause: the gate scanned its own file, whose header names AAASM-5750. That padded the site count with the gate quoting itself.

# severity defect
1 HIGH node's floor was satisfied entirely by the gate's own two self-references. Deleting the only real site left the suite green.
2 HIGH python's test_quickstart_negative_control.py splits Planned and its ticket across two lines. The same-line-only scan never saw it — the PR claimed coverage it did not have.
3 MED-HI go collected 6 sites against a floor of 5, so deleting one site, or merely reflowing a comment, kept it green with a stale referent in the tree.
5 MED all three asserted that every Planned in the repo names AAASM-5750. §6 scopes the term to any decided-but-unbuilt capability with any ticket, so the next unrelated roadmap row would have broken CI for a reason no reader could guess.
6 MED the bodies and failure messages attributed the referent rule to ADR 0033 §6. §6 requires a ticket reference and says nothing about which. The rule is AAASM-5750's own, and is now cited as such.

What the gate asserts now

Two assertions, each narrow enough to be true:

  1. No forward-looking claim defers to a closed measurement ticket. Planned or tracked as, paired with a ticket on its own line or the next, must not name AAASM-5731 or AAASM-5681. Those measured the absence; neither will build the sink. This never false-positives on an unrelated Planned.
  2. Every guarded path is still reachable by the scan — asserted as a set of paths, not a count. A count can be held up by an unrelated site appearing as a real one is deleted; naming them makes that substitution visible.

The gate file is excluded from its own scan, with a positive control proving the exclusion is scoped: the identical stale-referent line fails when placed in any other file.

Every probe that previously passed, re-run against the rebuilt gate

probe before after
delete the only/one real site green red — names the missing path
reflow so term and ticket split lines green red — the lookahead catches the stale referent
revert python's split-line site green red
stale referent on node's tracked as line unguarded red
unrelated roadmap Planned (AAASM-9999) red (wrong) green
stale referent inside the gate file n/a green — correct, and the positive control shows the same line fails elsewhere

The reviewer also disputed the AAASM-5755 rationale, and the dispute holds up: capability-manifest row G10 (governance/capability-manifest.yaml:5123-5168) files a measured audit drop as coverage: unmeasured, and governance/README.md:417-419 is normative — "If none fits, the answer is unmeasured, not a twelfth term." That is precedent pointing the other way. AAASM-5755 has been re-scoped from a directive into an adjudication: it now asks which term is right, and lists the outcome where go-sdk and python-sdk are the ones that get corrected. No claim in this PR depends on the answer.


Review round 3 — round 2 was too narrow, in the opposite direction

Round 2 replaced an over-broad assertion with a two-element denylist. Review found that this stopped the gate asserting the thing the change made true: repointing a guarded site to any non-stale ticket passed green, including a real sibling ticket.

ffi_governance_client.go:169   AAASM-5750 -> AAASM-9999  ->  ok
ffi_governance_client.go:169   AAASM-5750 -> AAASM-5749  ->  ok

The likeliest drift — AAASM-5750 gets split or superseded and someone updates the referent — was undetected. Round 1 was too broad; round 2 too narrow. Both directions are now covered by splitting the assertion:

site rule
guarded (a named audit-sink deferral) must name AAASM-5750 exactly
any other must merely not name a stale referent

The positive assertion is scoped to a named set, so it carries none of round 1's repo-wide over-breadth — the roadmap-row probe still passes.

A second defect round 2 introduced

The one-line lookahead had no directionality, and created a false-positive class the same-line rule could not produce. Forward-looking prose inserted above a correct backward citation was blamed for it:

153: // Streaming record delivery is Planned for a later release.     <- inserted, unrelated
154: // RecordResult discards the record and reports success (AAASM-5731).   <- pre-existing, CORRECT
FAIL: ffi_governance_client.go:153 defers to AAASM-5731

There are 81 backward citations across the three SDKs — go 30, python 33, node 18 — each a landmine for adjacent claim prose. None is adjacent today, so this was green by luck of layout rather than by construction.

The window now extends only when the claim line carries no ticket of its own and does not end a sentence. The reviewer's suggested fix (extend only within the same comment block) would not have worked — in the example above both lines are in one block. The sentence terminator is the discriminator that actually separates the two cases: the inserted line ends in ., python's genuinely wrapped site ends in §6.

Disclosed rather than fixed

  • The reachability check is per file, not per site. A guarded file that reflowed its real site out of reach and gained a second correct claim would keep its entry. Requiring every forward-claim line in a guarded file to pair was considered and rejected: tool_wrapper.go:115 ("which is what Planned names") is legitimate prose with no ticket and would fail. Needs two coordinated edits; no file carries more than one site today.
  • The excluded gate file is a hiding place. A test file that documents no SDK behaviour, and the exclusion matches one exact path rather than a prefix — verified with a positive control against a similarly-named neighbour.

Both are written into each gate's header.

Gates re-run

repo tests lint types
go-sdk 407 passed golangci 0 issues gofmt clean
python-sdk 1224 passed, 16 skipped ruff clean pre-commit mypy pass
node-sdk 665 passed, 2 skipped eslint 0 tsc 0

ADR 0033 §6 scopes `Planned` to "decided but not implemented — a ticket
reference". Both sites referenced AAASM-5681, which measured the absence of an
SDK-side audit sink but never intended to build one. Unlike go-sdk and
python-sdk — whose referent already points at a closed ticket — 5681 is still
open, so node is not yet broken. It would be the moment 5681 closes.

AAASM-5750 owns the capability. `with-assembly.ts`'s "tracked as" line is the
same kind of forward reference and moves with it. References citing AAASM-5681
as the ticket that *measured* the drop are left alone; those are still true.
The referent lives in a comment, and a comment is the one artifact in a source
file with no mechanical check on it.

Scope is narrower here than in the sibling SDKs, and the header says why: the
scan keys on the §6 term, and node-sdk currently describes one state with two
different terms — `Planned` in `gateway-governance.ts`, `Unmeasured` in
`with-assembly.ts` and the quickstart control. go-sdk and python-sdk both
reason explicitly that `Unmeasured` is wrong for a state whose stopping point
has been measured. Reconciling that is a claim change, not a referent change,
so it is filed as AAASM-5755; when it lands, those sites acquire the term and
this scan covers them with no change here.

A floor guards the scan itself: an empty walk and a clean tree otherwise
report the same result.
@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Independent review broke the first version three ways, and all three came from
one design mistake: the gate scanned its own file. Its header names AAASM-5750,
so the floor was partly satisfied by the gate quoting itself — in node it was
satisfied ENTIRELY that way, and deleting the only real site left the suite
green.

Four changes:

* **Exclude the gate file from its own scan.** Verified with a positive
  control: the same stale-referent line fails when placed in any other file.
* **Assert the expected SET of guarded paths, not a count.** A count can be
  held up by an unrelated site appearing as a real one is deleted; naming the
  paths makes that substitution visible.
* **Pair the claim with a ticket on its line OR the next.** Coverage was
  decided by where a comment happened to wrap — python's quickstart control
  split `Planned` from its ticket across two lines and was silently unchecked
  while the PR claimed it was covered. Reflowing a comment now cannot hide a
  stale referent.
* **Stop asserting that every `Planned` names AAASM-5750.** §6 scopes the term
  to any decided-but-unbuilt capability with any ticket, so the first version
  would have failed CI on the next unrelated roadmap row. The invariant is now
  the narrow one that is actually true: AAASM-5731 and AAASM-5681 measured the
  absence and will not fix it, so neither may ever be a forward referent.

The rule is also now attributed correctly. It comes from AAASM-5750's own
description, not from ADR 0033 §6 — §6 requires *a* ticket reference and says
nothing about which. A failure message citing an ADR for a rule the ADR does
not contain sends the next reader to the wrong document.
…the stale ones

Round-2 review: narrowing the invariant to a two-element denylist stopped the
gate asserting the thing the change actually made true. Repointing a guarded
site to ANY non-stale ticket passed green — including a real sibling ticket:

    ffi_governance_client.go:169  AAASM-5750 -> AAASM-5749  ->  ok

The likeliest drift — AAASM-5750 gets split or superseded and someone updates
the referent — was undetected. Round 1 was too broad, round 2 too narrow.

Two tiers, so neither failure mode returns:

* a **guarded** site (one of the named audit-sink deferrals) must name
  AAASM-5750 exactly;
* **any other** site must merely not name a stale referent, so an unrelated
  roadmap row is still legitimate.

The positive assertion is scoped to a named set, so it carries none of round
1's repo-wide over-breadth.

Also fixed: the one-line lookahead had no directionality, and created a new
false-positive class the same-line rule could not. A line of forward-looking
prose inserted above a correct BACKWARD citation was blamed for it:

    153: // Streaming record delivery is Planned for a later release.
    154: // RecordResult discards the record and reports success (AAASM-5731).
    FAIL: ...:153 defers to AAASM-5731

The window now extends only when the claim line carries no ticket of its own
AND does not end a sentence. There are 81 backward citations across the three
SDKs — go 30, python 33, node 18 — each a landmine for any adjacent claim
prose. Zero are adjacent today, so this was green by luck of layout.

Two residual limits are disclosed in the header rather than papered over: the
reachability check is per file rather than per site, and the excluded gate file
is a hiding place. Both measured as currently unreachable.
@sonarqubecloud

Copy link
Copy Markdown

@Chisanan232
Chisanan232 merged commit 5f1dbd6 into main Aug 13, 2026
25 checks passed
@Chisanan232
Chisanan232 deleted the v0.0.1/AAASM-5750/docs/planned_referent branch August 13, 2026 10:13
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