Skip to content

fix(cli+framework): fw-4.43.0 / cli-3.45.0 — close #416 and #415 - #417

Merged
montfort merged 1 commit into
mainfrom
fix/issues-415-416
Aug 7, 2026
Merged

fix(cli+framework): fw-4.43.0 / cli-3.45.0 — close #416 and #415#417
montfort merged 1 commit into
mainfrom
fix/issues-415-416

Conversation

@montfort

@montfort montfort commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Closes #416. Closes #415.

Two adopter reports with the same shape: the failure produced a message that looked normal.


#416refresh-suggest never found telemetry

The report was correct in every particular, including which of the two filenames was the right one to keep.

Builds Result
close.rs (writer) CHARTER-NN.telemetry.yaml — slug stripped, so the name survives a rename ✅ written
refresh_suggest.rs (reader) <NN-slug>.telemetry.yaml — from the Charter's own file stem ❌ never exists

Reproduced on a second repo before touching anything. Sentinel has 27 telemetry files, all canonical, and:

$ straymark charter refresh-suggest heartbeats
  ● CHARTER-02-gin-index-…  —   —  (missing)
  Chain length (closed Charters in window): 0

So the refresh heuristic — the mechanism that detects accumulated spec drift across a Charter chain — has been inert in every repo with closed Charters since the names diverged.

Why it outweighs its size: Chain shorter than 3 closed Charters with telemetry — heuristic not yet meaningful is indistinguishable from the normal early state. A seven-Charter chain ran past it without anyone suspecting a defect.

Fix. One canonical_telemetry_name in charter/mod.rs, used by both sides, with a fallback to the legacy name for telemetry older CLIs may have written. The regression test asserts what actually matters — not the string, but that writer and reader derive it from the same place.

After, on the same repo: CHARTER-02.telemetry.yaml resolved, chain length 1, rolling mean computed.

Also: the two thresholds were printed as bare numbers and read as contradictory. Each line now names what it gates — 3 is the sample size needed to evaluate, 6 is the value the mean must beat.

#415 — duplicate FU ids

The reported cause does not reproduce. Ids are already assigned per entry, not per AILOG — next_n += 1 has been inside the inner loop since before cli-3.41.0, and two AILOGs in one pass produce FU-001 and FU-002 correctly. Suggestion 1 was already implemented.

Two real paths, both reproduced:

  1. Parallel branches each computing max + 1 against their own copy, then merged — reproduced with the exact reported shape (same id, different Origin, different Source-hash). The followups: the registry is a guaranteed conflict between parallel PRs, and the correct resolution silently reverts closures #391 merge driver renumbers on merge; it was wired in no repo, which is what feat(cli): cli-3.44.0 — install-merge-driver, and correct what skipping it costs #414 addresses.
  2. Triage pruning. Pruning a closed entry to a provenance bullet removes its heading, max() drops, and the next drift --apply reissues the number. This one was documented in Sentinel's own registry on 2026-06-04"prune-to-provenance-bullet hides closed ids … collision reported upstream" — and went unfixed for two months.

Fixes.

  • The high-water mark now scans every FU-NNN mention in the registry body, so a pruned id stays retired.
  • find_entry_unique refuses an ambiguous id and names both entries, replacing first-match resolution in note / set-status / verify / promote / status.
  • New FOLLOWUP-DUPLICATE-ID rule, as an error — unlike most registry findings this one silently misdirects writes, and no reading of a duplicate id is intentional.

Docs

The telemetry convention was documented wrong in STRAYMARK.md (§10, §15) and QUICK-REFERENCE.mdin all three languages. The docs corroborated the reader, not the writer, so an adopter checking the name by hand would have found confirmation of the wrong one. Same correction in the charter amend --merge-into guidance the CLI prints.

(Correction to my first comment on #416: I said five files including SPECKIT-CHARTER-BRIDGE.md. It is four — my grep matched a line where NN-slug.md, which is correctly the Charter file, co-occurs with the word "telemetry".)

Verified

  • cargo test: 967 passed, 0 failed.
  • charter/mod.rs: 4 unit tests including writer/reader agreement.
  • duplicate_fu_ids_test.rs: 5 tests reproducing the reported sequence — the refused note/set-status leave the registry byte-identical; validate reports the duplicate; a clean registry stays silent (the rule keys on headings, so a cited id is not a second entry); a pruned id is not reissued.
  • Against real repos: refresh-suggest on Sentinel fixed as above; validate reports no duplicate ids there today (the operator repaired the FU-345 collision by hand before reporting).

Known limits

  • status now fails on an ambiguous id where it used to print something. Deliberate: showing one of two entries sharing a number is how an operator concludes the wrong one is the one they are about to write to. followups list still shows everything.
  • FOLLOWUP-DUPLICATE-ID being an error means a repo with existing duplicates starts failing validate, including in CI. Intended — the fix is mechanical and the hint says so. A warning would reproduce the original failure, which is that nothing said anything.
  • The legacy telemetry fallback is unverified against a real file — no adopter is known to have <NN-slug>.telemetry.yaml on disk. Added because the reporter suggested it and it costs one exists() call; the test covers resolution order, not a real-world case.

🤖 Generated with Claude Code

Two adopter reports, both silent-failure shaped: the failure produced a message
that looked normal.

#416 — charter refresh-suggest never found telemetry. close writes
CHARTER-NN.telemetry.yaml (slug stripped so the name survives a rename);
refresh_suggest built <NN-slug>.telemetry.yaml from the Charter's own file
stem. The reader never found what the writer wrote, so the refresh heuristic
has been inert in EVERY repo with closed Charters since the names diverged.
Reproduced on a second repo before touching anything: 27 telemetry files on
disk, every Charter reported (missing), chain length 0.

What makes it worse than its size: "Chain shorter than 3 closed Charters with
telemetry — heuristic not yet meaningful" is indistinguishable from the normal
early state, so a seven-Charter chain ran past it unsuspected.

Both sides now derive the name from one helper in charter/mod.rs, with a
fallback to the legacy name. The regression test asserts what matters — not the
string, but that writer and reader derive it from the same place. Also labels
the two thresholds (3 = sample size, 6 = trigger value) that were printed as
bare numbers and read as contradictory.

#415 — duplicate FU ids. THE REPORTED CAUSE DOES NOT REPRODUCE: ids are already
assigned per entry, not per AILOG, and have been since before cli-3.41.0. Two
real paths, both reproduced:

- Parallel branches each computing max+1 against their own copy, then merged.
  The #391 merge driver renumbers on merge — it was wired in no repo.
- Triage pruning a closed entry to a provenance bullet removes its heading, so
  max() drops and the next drift --apply reissues the number. This one was
  documented in Sentinel's own registry on 2026-06-04 and went unfixed for two
  months.

Fixes: the high-water mark scans every FU-NNN mention in the body, so a pruned
id stays retired; find_entry_unique refuses an ambiguous id and names both
entries, replacing first-match resolution in note/set-status/verify/promote/
status; FOLLOWUP-DUPLICATE-ID reports the state as an error, because unlike
most registry findings it silently misdirects writes.

Docs: the telemetry convention was documented wrong in STRAYMARK.md and
QUICK-REFERENCE.md in all three languages — the docs corroborated the reader,
not the writer.

967 tests pass. Work in AILOG-2026-08-07-001.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant