Skip to content

Adapter Node suite in CI; Item 4: null cash admitted only with the estimate-only marker; adapter writes the markers - #99

Merged
StepenkoAnatoli merged 8 commits into
mainfrom
ci/node-adapter-and-item4
Oct 18, 2026
Merged

StepenkoAnatoli merged 8 commits into
mainfrom
ci/node-adapter-and-item4

Conversation

@StepenkoAnatoli

@StepenkoAnatoli StepenkoAnatoli commented Oct 18, 2026 •

Copy link
Copy Markdown
Owner

Problem and resulting behavior

Two of the "Remaining limits" of #98, solved:

  1. The adapter's Node suite was not run by the repository's gate. .github/workflows/regression-gate.yml gains a job adapter-tests (display name claude-code-adapter-tests): the same pinned checkout, actions/setup-node pinned by sha (v7.0.0, the pin Research-Kit's workflows use) with Node 24, then node --test hosts/claude-code/route.test.mjs. It runs on every trigger the gate job runs on and is not a required status context (branch protection is the maintainer's setting). Its first run on this PR passed (93 tests). The adapter README says CI runs the suite.
  2. tools/conform_spec.py refused every record a subscription host writes because its cash fields are null (proposal docs/proposals/usage-windows-gate4.md, Item 4). Accepted as proposed on 2026-10-18: counters.cash-spent and cash-cap may be null only beside counters.cash-basis: "estimate-only", and evidence.actual-spend only beside evidence.actual-spend-basis: "estimate-only"; an unmarked null keeps today's violation text; any other marker value is a violation; a marker beside a finite number is allowed. The additive fields are written into §10.3 and §10.5 of skills/smart-router/references/spec-v2.md (the normative definitions live there, not under docs/; the maintainer's decision covers that amendment), docs/USAGE_TELEMETRY.md, the proposal's review record and the CHANGELOG. The host-artifact check accepts the marker and refuses any other value. tools/outcome_ledger.py, the canonical outcome store, applies the same rule.
  3. The host adapter now writes the markers (hosts/claude-code/, refreshed from the host): every ledger record carries cash-basis, an outcome with a null spend gets actual-spend-basis (a supplied basis is validated: null is no basis, any value but estimate-only refused). Older committed lines stay unmarked and are still refused, as the adapter README says. The trace also gains the five units the adapter routed since Claude Code host adapter, usage-window affordability proposal, calibration evidence, two test-isolation and two link fixes #98 (two of them this change's own build units, three MoonAliza fix units).

Related issue

#98 "Remaining limits or risks" (items 1 and 5); proposal Item 4 — no issue number.

Validation

Run from the repo root on this branch (50e5107), local fixtures, no live provider:

  • python3 tools/run_regression.py → "REGRESSION GATE: all checks PASS" (through the pre-commit hook on every commit)
  • python3 tools/test_conform_spec.py → 29 OK (9 new K10 tests, red-first with 7 guard-removal proofs); python3 tools/test_claude_code_host_artifacts.py → 5 OK; python3 tools/test_outcome_ledger.py → 11 OK (one new test, red-first, guard proof)
  • python3 tools/validate_skills.py --strict exit 0; python3 tools/check_secrets.py clean (0 hits)
  • node --test hosts/claude-code/route.test.mjs (Node 24) → 93 pass, 0 fail, locally and in the new CI job
  • python3 tools/conform_spec.py --record <the newest ledger line> → CONFORMANT; --outcome hosts/claude-code/trace/outcomes/sr-ci-item4-3.json → CONFORMANT; --record <the first, unmarked ledger line> → VIOLATION (counters.cash-cap must be a finite non-negative number), as intended
  • CI on f2cd97c: regression-gate, claude-code-adapter-tests and watcher-once-proof all success

Remaining limits or risks

  • The adapter's older trace lines predate the marker and remain non-conformant by design.
  • The commit message of 50e5107 says "12 tests OK"; the file runs 11 (the count in the message is off by one, the result is not).

🤖 Generated with Claude Code

https://claude.ai/code/session_01VdJ51CTnHT4Zet6eScsBBh

StepenkoAnatoli and others added 8 commits October 18, 2026 04:29
…orkflow

What changed: .github/workflows/regression-gate.yml gains the job adapter-tests
(display name claude-code-adapter-tests, ubuntu-24.04): the same pinned
actions/checkout step as the other jobs, actions/setup-node pinned by sha
(v7.0.0, the pin Research-Kit's workflows use) with Node 24, then
`node --test hosts/claude-code/route.test.mjs`. The header comment says it is
not a required status context. hosts/claude-code/README.md says CI runs the
suite; the artifact test's docstring and CHANGELOG (Unreleased) say the same.

Why: PR #98's remaining limits: the adapter's 91-test suite was run by no
gate, local or CI.

What you verified: yaml.safe_load parses the workflow and the job has the
name, runner and three steps above (verified). The job's command under Node
v24.21.0 locally: 91 tests, 91 pass, 0 fail (verified). The job itself has
not run on GitHub Actions (untested). test_claude_code_host_artifacts.py OK,
validate_skills --strict exit 0, check_secrets clean (verified); the
regression gate ran in the pre-commit hook.

What you got wrong: the first header comment said the job runs "on push and
pull_request"; with no `if:` it runs on every trigger the gate job runs on
(dispatch and schedule too). Reworded before committing; yaml re-parsed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdJ51CTnHT4Zet6eScsBBh
…er (Item 4)

What changed: tools/conform_spec.py. check_record: counters.cash-spent and
counters.cash-cap may be null only when counters["cash-basis"] ==
"estimate-only". check_outcome: evidence.actual-spend may be null only when
evidence["actual-spend-basis"] == "estimate-only"; every other Outcome field
still goes through outcome_ledger.validate (on a copy with a placeholder
spend; the document is not modified). An unmarked null keeps today's text; a
marker with any other value is a new violation ('LedgerRecord
counters.cash-basis must be "estimate-only" when present', and 'Outcome
evidence.actual-spend-basis ...' likewise); a marker beside a finite number
is allowed. tools/test_conform_spec.py: K10, nine tests. The artifact test's
docstring no longer says the record check is never relaxed.

Why: docs/proposals/usage-windows-gate4.md Item 4, accepted by the
maintainer on 2026-10-18: a subscription host cannot write a conformant
record without inventing 0.0 cash, which USAGE_TELEMETRY forbids.

What you verified: K10 red before the change (21 failures, 2 errors: marked
null refused, wrong marker accepted, CLI exit 1) and 29/29 OK after
(verified). Guard removal, each restored after: marker-value check removed
-> 12 wrong-marker record subtests red; record null admission removed ->
marked-null record test and CLI test red; null admitted without marker ->
unmarked-record pin red; outcome marker check removed -> 8 subtests red;
outcome null admission removed -> marked-null outcome and CLI red; outcome
null admitted without marker -> unmarked-outcome pin red (verified). A
committed adapter ledger line and outcome: VIOLATION unmarked, CONFORMANT
with the marker added (verified). tools/outcome_ledger.py (the store) is
unchanged and still refuses a null spend (expected, out of scope).

What you got wrong: nothing to report.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdJ51CTnHT4Zet6eScsBBh
…LEMETRY, the proposal and CHANGELOG

What changed: skills/smart-router/references/spec-v2.md §10.3 Outcome gains
evidence.actual-spend-basis and §10.5 LedgerRecord gains counters.cash-basis,
one line each (optional, additive §13, only "estimate-only", the one case
where the cash field may be null). docs/USAGE_TELEMETRY.md (beside the
"stays null, never zero" line): a record or outcome with unknown cash carries
the marker. docs/proposals/usage-windows-gate4.md: the review record carries
the 2026-10-18 decision (Item 4 accepted as proposed and implemented with
this change; Items 1-3 remain proposals; no independent non-author verdict
recorded), and the status line no longer says nothing in skills/ is amended.
CHANGELOG.md: the Unreleased entry for Item 4.

Why: the maintainer accepted Item 4 on 2026-10-18; the checker change
(previous commit) needs the contract to name the fields it admits.

What you verified: validate_skills --strict exit 0, check_secrets clean,
tests/docs_drift.py pinned (30 skills docs) (verified); nothing in tools/ or
tests/ parses the spec's JSON blocks (git grep, verified); the regression
gate ran in the pre-commit hook.

What you got wrong: the brief said the §10.3/§10.5 definitions are under
docs/; they are in skills/smart-router/references/spec-v2.md (a normative
file). Edited there, and flagged in the report. The first status-line edit
left one over-long line and "the items below" still covering Item 4;
reflowed to name Items 1-3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdJ51CTnHT4Zet6eScsBBh
… and refuses any other value

What changed: tools/test_claude_code_host_artifacts.py. The per-line ledger
checks move into check_ledger_line (same assertions, seq order stays with
the caller), which now also requires the optional counters.cash-basis, when
present, to be "estimate-only". Two fixture tests: a line with null cash and
the marker passes the key check and conform_spec.check_record; a line with
a wrong marker ("estimate", "", None, 0) fails the key check.

Why: Item 4 (accepted 2026-10-18). The next adapter refresh writes
counters.cash-basis; the gate's artifact check must accept that and must not
accept a different value that conform_spec now refuses.

What you verified: after the pure refactor the file was OK (5 tests before
the fixtures were added: 3, OK) (verified). With the fixtures and no marker
check: the marked fixture passed and the wrong-marker test failed 4 subtests
(verified). With the check: 5 tests OK; check line replaced by `pass`: 4
failures, restored: OK (verified). Every one of the 31 committed ledger
lines with cash-basis added passes check_ledger_line and
conform_spec.check_record (verified). validate_skills --strict exit 0,
check_secrets clean (verified); the regression gate ran in the pre-commit
hook.

What you got wrong: the brief's "red-first: a fixture record with the marker
must pass the key check" could not go red: the key check was already a
subset test (LEDGER_KEYS <= keys, COUNTER_KEYS <= counters), so an extra
marker key always passed. The red half is the wrong-marker fixture. The
file has no outcome-evidence check at all (it never reads trace/outcomes/),
so there was no actual-spend-basis key check to relax; none was added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdJ51CTnHT4Zet6eScsBBh
…ll actual-spend

What changed: CHANGELOG.md (the Unreleased Item 4 entry) and the review
record in docs/proposals/usage-windows-gate4.md each gain a "known limit"
note: the reference §10.3 store, tools/outcome_ledger.py, is not amended by
Item 4; validate and record still refuse an Outcome whose
evidence.actual-spend is null (marked or not), and read_all fails closed on a
ledger holding such a line. Bringing the store in line is a follow-up.

Why: review finding R2 (S3). conform_spec now accepts a marked-null Outcome
that the repository's own store refuses. The brief scoped Item 4 to the
checker and named its files; outcome_ledger.py is not among them and the
brief's stop trigger covers a change outside them, so this commit takes the
finding's documented alternative (record the gap) and leaves the code change
to a follow-up unit. Set aside: changing outcome_ledger.validate here.

What you verified: reproduced the gap on an Outcome with actual-spend null
and actual-spend-basis "estimate-only": conform_spec --outcome prints
CONFORMANT (exit 0); outcome_ledger.validate and record raise FailClosed
"evidence actual-spend must be a finite non-negative number"; read_all on a
one-line ledger fails closed "ledger line 1 invalid" (verified).
validate_skills --strict exit 0, check_secrets clean, docs_drift pinned
(verified); the regression gate ran in the pre-commit hook.

What you got wrong: nothing to report.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdJ51CTnHT4Zet6eScsBBh
…ine width

What changed: tools/test_claude_code_host_artifacts.py module docstring,
lines 6-8 (now 6-9) rewrapped to about 105 columns; same words, no code
change.

Why: review finding R3 (S4). The Item 4 reflow left line 6 at 174 characters,
wider than any line in the file at base (143).

What you verified: before, line 6 was 174 characters (awk, verified red);
after, the docstring lines are 101-108 and the file's maximum is 143, the
base value (awk, verified green); the docstring's words are unchanged
(whitespace-normalised diff against HEAD, verified); the file's 5 tests pass
(verified); the regression gate ran in the pre-commit hook.

What you got wrong: nothing to report.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdJ51CTnHT4Zet6eScsBBh
…arries the estimate-only cash markers (Item 4), and its newest ledger line and outcome pass conform_spec

The host adapter writes counters.cash-basis "estimate-only" on every ledger record and actual-spend-basis "estimate-only" on an outcome whose actual-spend is null (a supplied basis is validated: null is no basis, any other value is refused). Older committed lines stay unmarked and conform_spec keeps refusing them, as the README says. The trace gains the sr-item4-host and sr-ci-item4 units (decisions, dispatches, accepted outcomes) and the fix-x2-1, fix-x2-2 and fix-u7-r3 decisions and dispatches (the first MoonAliza units routed by the adapter). The copy carries no build briefs.
…te-only marker (Item 4), as conform_spec does

what changed: tools/outcome_ledger.py validate(): a null spend is valid beside actual-spend-basis "estimate-only"; a present marker with any other value is refused ('evidence actual-spend-basis must be "estimate-only" when present'); the docstring names it. tools/test_outcome_ledger.py: one test (marked null accepted; unmarked null keeps today's refusal; six wrong markers refused; a marker beside a number allowed).
why: the R2 follow-up recorded in this branch: the canonical outcome store still refused the records conform_spec now accepts.
what you verified: red first on the unchanged module (the new test errors with 'finite non-negative number' on the marked null); green after the change (12 tests OK); guard removal (the marked-null clause replaced by False) makes it red again and the module was restored from a saved copy; the regression gate runs in the pre-commit hook (verified by the commit landing).
what you got wrong: the first draft of the test used names the module does not export (GOOD, validate, FailClosed bare); it errored on both sides of the change and was rewritten on the file's own helpers (good(), ol.validate, ol.FailClosed) before the red run was taken.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdJ51CTnHT4Zet6eScsBBh
@StepenkoAnatoli
StepenkoAnatoli marked this pull request as ready for review October 18, 2026 05:11
@StepenkoAnatoli
StepenkoAnatoli merged commit ade3f1e into main Oct 18, 2026
5 checks passed
@StepenkoAnatoli
StepenkoAnatoli deleted the ci/node-adapter-and-item4 branch October 18, 2026 05:24
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