Releases: thomas-powers-jr/cadence
Release list
v1.60.0
Package Changelog
Minor Changes
- 3d99185: Makes the dispatch contract enforceable at record time, closing the 2026-07-18 deja incident's three recommendations. A new optional
stop:DRAFT task field renders as a**Stop condition:**packet line, andcadence draft checkwarns (never blocks) when a task declaresfiles:with nostop:.cadence build task <id> --status=DONEnow runs a boundary + redundancy check at record time from real git diffs rather than agent self-report: a stray file outside the task's declaredfiles:refuses the recording (exit 1, no mutation) onceboundaryEnforcementresolves toblock, unless--allow-boundary-breachis passed (records anyway, emits an error-severity anomaly). Independent of that config field, one task recorded with--execution dispatchescalates boundary enforcement toblockfor the rest of the phase and never de-escalates.--isolationand--model-classround out the new recording flags; all three carry through toSUMMARY.jsonon settle when present. Fully additive: noschemaVersionbump, no.default()on any new field, and the existing settle-timeboundary-scangate is unchanged. - 06d8790:
cadence dispatch plannow computes an advisory execution verdict per task —{ execution: 'inline'|'dispatch', modelClass, model, reasons[] }— givingconfig.subagentPolicyandconfig.modelPerClasstheir first consumer. A new optionalclass:DRAFT task field (TaskZ.class) lets an operator declare a task's execution class; a pure heuristic cross-checks it and a mismatch surfaces as acadence draft checkcoherence warning.--jsonoutput gains the new per-task fields plus a top-levelsignals.contextUtilization(alwaysnullfor now — no real context-utilization signal is wired in yet). The rendered dispatch packet gains an**Execution:**line (and a**Model:**line when dispatched). Fully additive: noschemaVersionbump, no change to existing fields, anddispatch planremains read-only/advisory only — it does not spawn, schedule, or supervise agents.
Patch Changes
- Updated dependencies [3d99185]
- Updated dependencies [06d8790]
- @thomas-powers-jr/cadence-types@1.60.0
Published Packages
All public packages are published on npm as 1.60.0:
@thomas-powers-jr/cadence-core@thomas-powers-jr/cadence-host-claude-code@thomas-powers-jr/cadence-host-codex@thomas-powers-jr/cadence-host-toolkit@thomas-powers-jr/cadence-types
Verification
- npm publish completed with provenance in the Release workflow.
- Remote tag
v1.60.0is verified before the GitHub Release is created. - npm package versions and GitHub Release metadata are verified after publish.
- Workflow run: https://github.com/thomas-powers-jr/cadence/actions/runs/31908855082
v1.59.0
Package Changelog
Minor Changes
-
6e5a2d0: Added
cadence demo— a fully non-interactive refuse-then-succeed walkthrough (a real DRAFT→BUILD→SETTLE loop against an assertion-mode gutted-but-green fixture, then the honest fix) that runs in an ephemeral sandbox and cleans up by default.--keepleaves the playground on disk,--in-placeruns inside the current directory (refusing loudly instead of overwriting an existing.cadence/there),--interactive/-iopts into the tutorial's TTY-paced pauses. A barenpx @thomas-powers-jr/cadence-coreor barecadenceinvocation now dispatches straight into it.cadence tutorialkeeps working unchanged, with one added stderr line pointing atcadence demo.Added a minimal progressive-disclosure onboarding-stage system: a global
~/.cadence/onboarding.json(or$CADENCE_HOME/onboarding.json) stage marker (0 First Contact, 1 Driver, 2 Operator, 3 Power User) that a successfulcadence demorun advances to at least Driver.cadence helpandcadence startnow hidedoctorbelow stage 2; a new top-level--advancedflag forces the full surface at any stage. Filtering is display-only — every command stays registered and directly invocable (cadence doctor,cadence start --pick 6) regardless of stage.
Patch Changes
- dd6c3c5:
--filter-regex(onrecommendation list/decision list/assumption list) now rejects patterns with nested quantifiers that can cause catastrophic backtracking (e.g.(a+)+) before compiling the operator-supplied pattern, addressing a CodeQLjs/regex-injection(ReDoS) finding onpackages/core/src/cli/list-filter.ts.- @thomas-powers-jr/cadence-types@1.59.0
Published Packages
All public packages are published on npm as 1.59.0:
@thomas-powers-jr/cadence-core@thomas-powers-jr/cadence-host-claude-code@thomas-powers-jr/cadence-host-codex@thomas-powers-jr/cadence-host-toolkit@thomas-powers-jr/cadence-types
Verification
- npm publish completed with provenance in the Release workflow.
- Remote tag
v1.59.0is verified before the GitHub Release is created. - npm package versions and GitHub Release metadata are verified after publish.
- Workflow run: https://github.com/thomas-powers-jr/cadence/actions/runs/31849447692
v1.58.0
Package Changelog
Minor Changes
-
85fc5d2: Added a new
cadence doctorcheck,recommendation-archive-currency, that warns when a recommendation in the activerecommendations[]array carries a terminalshipped/rejectedstatus without being moved into thearchived[]array — the invariant phase 276 had to hand-backfill for 21 recommendations that predated the auto-archive feature. Warns naming each offending id, title, and status, with remediation pointing atcadence recommendation archive <id>.convertedandsettle-pendingare deliberately excluded from the flagged-status set: a converted recommendation's only schema-documented successor state issettle-pending(reached solely via the settle hook), notarchived, so flagging it would emit wrong remediation.Diverging from the two adjacent ledger-reading doctor checks (
recommendation-shipped-drift,orphaned-evidence), a malformed/schema-invalidrecommendations.jsonreportsindeterminate, never a silent best-effortok— a genuinely missing file still reportsok(the normal fresh-repo state).fixIdis alwaysnull: archiving is evidence-gated per record, not a safe blind auto-repair, so--fixnever touches it.
Patch Changes
- @thomas-powers-jr/cadence-types@1.58.0
Published Packages
All public packages are published on npm as 1.58.0:
@thomas-powers-jr/cadence-core@thomas-powers-jr/cadence-host-claude-code@thomas-powers-jr/cadence-host-codex@thomas-powers-jr/cadence-host-toolkit@thomas-powers-jr/cadence-types
Verification
- npm publish completed with provenance in the Release workflow.
- Remote tag
v1.58.0is verified before the GitHub Release is created. - npm package versions and GitHub Release metadata are verified after publish.
- Workflow run: https://github.com/thomas-powers-jr/cadence/actions/runs/31769066620
v1.57.0
Package Changelog
Minor Changes
-
c582da3:
deep-verifyandper-task-verifynow persist the provider/model identity that actually ran them into a settle'sgates[]array — previously neither gate recorded any identity there at all (unlikecode-review/security-audit), so an operator readingSUMMARY.jsonhad no way to tell whether either had run under a real verifier or themockplaceholder.The new fields —
observedProvider,observedModel, and (forper-task-verify)taskId— are structurally separate from the existingprovider/modelfields onGateProvenanceZ, soderiveAssuranceRecord's assurance rollup, which foldsgates[].provider/.modelby field name, stays completely blind to them. This is deliberate: this repo's own verifiers already run ashost-cli(non-mock), so naively feedingdeep-verify's andper-task-verify's identity into the existing rollup fields would silently inflateassurance.overalltowardstrongon ordinary settles where no review gate actually ran. The safety property is proven by tests on the existing fold code, not by adding a new exclusion branch to it.per-task-verifynever previously appeared ingates[]at all — it runs during BUILD, not settle. Settle now synthesizes one entry per task carrying a persistedPerTaskVerifyRecord, prepended to the front of the array (per-task-verify's work completed before this settle's own gate loop starts, and prepending preserves the existing convention — used throughout this repo's test suite — that the last entry ingates[]is the gate that most recently ran or refused during this settle).All three new fields are additive and
.optional()with no default and noschemaVersionbump — absent on every historicalSUMMARY.json, andcomputeSummaryContentHashis unaffected. -
4901a00:
cadence resumenow warns whenstate.json'ssession.lastHandoffpointer names aSESSION-*.mdfile that no longer exists. PreviouslylocateFreshestHandoffsilently fell back to the freshest-by-generated_atdoc in.cadence/handoff/with no signal that the pointer was dangling, so a stale-but-plausible doc could read as authoritative. The warning names both the missing pointer filename and the doc actually served, and is rendered as its own message distinct from the existing loop-position drift banner, on both thecadence resumeCLI text surface and theresumeService/MCPCommandIOsurface.ResumeResult(@thomas-powers-jr/cadence-types) gains an additive, optionaldanglingHandoffPointerfield carrying the missing pointer's filename when this fires. Absent on every normal resolution path (no pointer ever set, or the pointer names a file that exists). -
492a388:
settle run --deepno longer refuses (or requires--force) on an Acceptance Criterion whose satisfaction condition is structurally circular — it depends on the verySUMMARY.md/SUMMARY.jsonthat settle produces, which doesn't exist until after the deep-verify pass that would need to observe it. A new pure classifier (classifyAcObservability) detects this narrow shape from an AC's Given/When/Then text and routes it to a distinctunobservableverdict instead of an ordinaryfail.unobservable-marked ACs are excluded from deep-verify's offenders list, the evidence-floor gate, and the force-used honesty report'sdeep:bucket — but never rolled up as a pass, and never allowed to moveassurance.overalltowardstrong.SUMMARY.mdand the CLI's summary-render surface render such ACs distinctly from both PASS and FAIL, carrying the classifier's reason, so an operator can tell "wasn't checked because it structurally can't be" from "checked and failed."DeepVerdictZ(@thomas-powers-jr/cadence-types) gains an additive, optionalunobservableboolean field. Absent on every historicalSUMMARY.jsonand on every AC this classifier doesn't flag;computeSummaryContentHashis unaffected. The classifier defaults toobservableon any ambiguity — a false negative is just an ordinaryfail, while a false positive would silently excuse a real failure, so every trigger pattern is narrow and structural (case-sensitiveSUMMARYtoken, quote-scope and negation-scope guards) rather than a broad keyword sweep.
Patch Changes
- Updated dependencies [c582da3]
- Updated dependencies [4901a00]
- Updated dependencies [492a388]
- @thomas-powers-jr/cadence-types@1.57.0
Published Packages
All public packages are published on npm as 1.57.0:
@thomas-powers-jr/cadence-core@thomas-powers-jr/cadence-host-claude-code@thomas-powers-jr/cadence-host-codex@thomas-powers-jr/cadence-host-toolkit@thomas-powers-jr/cadence-types
Verification
- npm publish completed with provenance in the Release workflow.
- Remote tag
v1.57.0is verified before the GitHub Release is created. - npm package versions and GitHub Release metadata are verified after publish.
- Workflow run: https://github.com/thomas-powers-jr/cadence/actions/runs/31754396940
v1.56.0
Package Changelog
Minor Changes
-
79a760a:
cadence initnow presents the verifier-provider choice explicitly: unless an explicit--verifier-provider <mock|anthropic|local|host-cli>flag,--activate, or--fullalready settled it, init asks which provider should back deep-verify — withmocklisted as a normal, unshamed, first-class option rather than a fallback to feel bad about. The prompt fires only when a prompter is available (a real TTY, orCADENCE_PROMPTER_SCRIPTfor scripted/CI runs); with no prompter available it silently defaults tomock— never coerced onto a real provider.On every completed scaffolding run — flag-resolved, prompted, or defaulted — the choice is now recorded as a retrievable decision in
.cadence/intelligence/decisions.json(viewable viacadence decision list), so no repo runs indefinitely under an inherited default without the operator having made or seen that choice.--dry-runcontinues to preview the resolution without prompting or writing a decision.Non-interactive paths with no prompter available (no TTY, no
CADENCE_PROMPTER_SCRIPT) and explicit-flag paths (--verifier-provider/--activate/--full) resolve exactly as before, just with the resolution now logged. Scripted (CADENCE_PROMPTER_SCRIPT-driven) runs against a repo with.claude/present now need one additional scripted answer ahead of the pre-existing host-wire question, since the new verifier-provider prompt asks first — existing scripts relying on the old single-answer convention should account for this. If the script runs out at the host-wire step, that step degrades gracefully — loud stderr notice, exit 0, scaffold intact — rather than failing the run. -
e228a6f: Added
cadence summary verify-all, an in-process sweep that walks every<id>-SUMMARY.jsonunder.cadence/phases/**and verifies each one the same waysummary verify <phase> <num>does, without spawning a CLI subprocess per file. Reports MISMATCH and any load/parse/schema failure as a failure, treats NO_HASH as informational only, and exits nonzero iff at least one file failed.This closes a growing correctness gap in this project's own CI: the corpus-wide
summary verifysweep test (phase 257) previously spawned one subprocess per historical summary (275+ and growing), which was closing in on the Windows CI timeout as the corpus grew. It now runs as a single process.Also fixes a related, independently-confirmed Windows CI timeout: the
skill-invokeFIFO-cap-at-100 hook-dispatcher test drove 105 serial real-disk state read/write round trips. The cap logic is now a pure function (applySkillInvoke), unit-tested directly with no I/O — internal only, no CLI-visible behavior change. -
14288c5: Added a new
cadence doctorcheck,conduction-drift-streak, that answers the trend question phase 251'sconduction-reachabilitycouldn't: not just "can this repo conduct a real finding" but "has it, lately." It's a read-only, best-effort utility walking the settled-phase.cadence/phases/**/*-SUMMARY.jsoncorpus in chronological order and counting the consecutive most-recent settles that carried no non-mock provider identity inassurance.verifierRollup— the same drift that let 263 settles accumulate undermockwith zero escalation, per the v1.54 audit. Also surfaced (without escalation) incadence status.DoctorSeveritygains a fourth rung,indeterminate: a check that could not assess the repo at all (e.g. an unreadable or malformed SUMMARY record whose true chronological position can't be ruled out as the most recent) — distinct fromok's "assessed, no problem found." Every existing consumer (DoctorReport.ok's roll-up, thefail()helper,cadence doctor --fix's fix-planner, the CLI/JSON renderer,doctorNextStep's Next-step guidance, and the MCPdoctorServiceseam) handles it explicitly —indeterminaterolls up likewarning(never fails the exit code) but is never counted as a problem and never silently folded into "all checks passed."Once the streak reaches 3 consecutive mock-only settles, the check escalates from
oktowarning— a warning only, never a settle refusal. That threshold is explicitly provisional (borrowed from an unrelated decision'sconfig.convergence.maxAttemptsdefault as a placeholder, not yet independently measured for this check) and says so in both the code and the rendered output; a follow-up will validate it once enough real-provider settles accumulate under the now-standard profile.Every pre-existing doctor check's rendered output and exit code is unaffected — a fixture corpus and regression suite cover the counter's chronological-ordering, malformed-data, and pre-existing-schema edge cases.
-
688f88f: Added a new
cadence doctorcheck,release-currency, that warns when the local repo's publishable content has drifted from what npm actually serves under the matching version — closing the gap behind a real incident where apackage.jsonenginesbump landed onmainbut the previously-published tarball under the same version string still declared the old floor, undetected for days because nothing ever compared content, only version numbers.It compares local
packages/core/package.json'senginesfield against npm's publishedenginesfor that package (npm view <pkg> engines --json), and independently flags any pending.changeset/*.mdfiles awaiting release, naming each one's bump type (when reported on its own, wording escalates if any pending changeset declares amajororminorbump). Both signals fold into a singlewarning-severity finding (nevererror) withfixId: null: this is a manual, judgment-call fix (cut a release, or confirm the divergence is intentional), never auto-applied by--fix.Fully best-effort and non-blocking. If the local
package.jsonis missing, unparseable, orprivate: true, the whole check is skipped with a silentok. If thenpm viewfetch fails — no network, an unpublished/private package, or a timeout — only theenginescomparison is skipped; the pending-changesets signal is still evaluated. It never throws and never fails thecadence doctorexit code on its own. -
3e6019f: Added a new read-only diagnostic,
cadence verify historical-coverage-audit, that audits every pre-phase-239 (coverageSchemeabsent)SUMMARY.jsonrecord's recorded AC PASS for genuine, attributable test evidence — answeringrec-20260729-006.Each AC classifies into one of four buckets, computed from only that phase's own literal (non-wildcard), on-disk declared test files:
self-attested(a token match in a file no other phase's DRAFT declares literally — high confidence),self-attested-shared(a match, but only in a file 2+ phases also declare literally — cannot rule out belonging to another phase's identically-numbered AC),not-found-in-declared-files(declared files were scanned, token not found — no repo-wide fallback), andunreachable(no literal, existing test file declared at all). It never performs a repo-wide bare-AC-Ntoken scan (395 of 448 test files in a real corpus can contain that token as unrelated fixture data) and never resolves wildcard-globfiles:entries. Purely additive and read-only:cadence verify phase's existingindeterminatecontract and command path are unmodified.--jsonemits the full per-phase report; human mode prints aggregate bucket totals and an unreadable-record count. Exit code is always0on a successful run (a diagnostic, not a gate) and1only if the audit itself fails to run. -
a66c412: Mock no longer records a persisted
passfor the five review-family gates (code-review,security-audit,plan-review,spec-review,ui-spec-review) — it abstains instead.verify()still dispatches exactly as before under mock (its deterministic checks — flagging an addedconsole.log(as HIGH, AC↔test linkage, etc. — still run and can still refuse), but when the resolved identity is mock and the outcome is a genuinely clean pass, the persisted record is relabeled rather than left as an unqualified pass:code-review/security-auditgate provenance recordsstatus: 'skipped'with askipReasonnaming the abstention (instead of'ran'), andplan-review/spec-review/ui-spec-review's convergence sidecar (*-PLAN-REVIEW.json/*-SPEC-REVIEW.json/*-UI-SPEC-REVIEW.json) gains a new optionalmockAbstained: truefield on the relevant history entry. A mock-servedrefuse(a real finding was flagged) is never relabeled — a refusal is never false confidence, regardless of provider.This closes the false-clean-pass gap where an empty diff, or a diff with no matching pattern, was recorded identically to a genuine review having run and found nothing.
deep-verifyandper-task-verifyare unaffected — they enforce real AC↔test linkage under mock and keep their existing pass/fail semantics unchanged.GateProvenanceZ/ConvergentReviewHistoryEntrygain no required fields and no schema-version bump — both additive, matching the phase 239/263 precedent; every historicalSUMMARY.jsonand convergence sidecar still parses, and no historical review-gate pass record is reinterpreted (the new fields apply only to settles/reviews run after this change).The repo's own
.cadence/config.jsonprofilemoves offautotostandardin this same release, closing a previously-deferred baseline-profile decision — mock abstention removes the false-confidence risk that baseline change would otherwise have carried. Seedocs/handoffs/HANDOFF-v1.56-verifier-honesty.md(Phase P) for the full design history. -
ca61066: Added
providerSelectionto persisted gate provenance, distinguishing three previously-indistinguishable states behind aprovider: 'mock'entry: a deliberately configured provider (including a deliberately configuredmock), a silent fallback to mock (at selection time in `createVerifierFactory...
v1.55.0
Package Changelog
Minor Changes
-
c8333f8: Added a new
cadence doctorcheck,conduction-reachability, that reports — separately forcode-reviewandsecurity-audit, since the two gates are asymmetrically gated in this repo — whether the current configuration can produce a real-provider (non-mock) finding at all.Two independent, deliberately-retained blockers make this structurally unreachable in normal, headless-agent-driven operation: the
autogate profile excludes both review gates from every tier, and the self-invocation guard forces amockverifier fallback whenevercadenceis already running inside a headless Claude Code session. A third, ordinary (non-safety-related) blocker can also apply: a gate's ownproviderconfig being set to'mock'.The check evaluates three axes per gate — profile inclusion (
gatesForacross all tiers), provider configuration (seamProvider), and the self-invocation session guard (conditioned on the gate's own provider being'host-cli', since the guard only applies to that spawn path) — and reportsseverity: 'warning'naming exactly which axis or axes block each gate, withfixId: null(no safe auto-repair exists; every remediation is an operator decision).status: 'ok'only when both gates are fully reachable.Neither blocker is modified or bypassed by this change —
isSelfInvocation,SELF_INVOCATION_ENV_VAR, and theDELTASgate matrix are untouched. The check adds visibility only, so an operator can tell "no real finding has been produced yet" apart from "no real finding can currently be produced," anddocs/providers.mdnow documents the exact operator procedure (a DRAFT-levelprofile:override, run from a real interactive terminal) to produce one when needed. -
db8209f: Fixed a real coverage-scanner defect: the JS/TS
test-coveragegate'sclassify()state machine had no concept of a regex literal, so a paren, quote, or backtick inside an unrecognized/regex/— not just parens/backticks, as originally reported — was read as a real structural character. This corruptedfindMatchingParenIndex's depth-aware paren matcher and/or flipped the scanner into real string/template mode for the rest of the file, silently undercounting or dropping test-block spans (and, in rarer cases, silently dropping a real assertion from a span without changing its count). A repo-wide sweep found this affected 20 of this repo's own 446 JS/TS test files before the fix; all 20 are now confirmed resolved with no file-content edits needed, since the fix lives entirely in the scanner.classify()(packages/core/src/verify/coverage-profiles/mask.ts) now recognizes JS/TS regex literals as their own lexical category, opt-in per language profile via a newLanguageSyntax.regexLiteralsfield (set only for the built-injs-tsprofile — no other language profile is affected). Regex-vs-division disambiguation uses a masker-only heuristic (no new runtime dependency) against an explicitly documented, bounded preceding-token vocabulary; a/in a context outside that vocabulary resolves conservatively, the same as division, rather than guessing regex-open.That conservative fallback is now also surfaced instead of staying silent:
cadence verify coverage --explainreports a[mask diagnostic]line naming the out-of-vocabulary context, so a scanner blind spot is visible instead of quietly under-counting coverage.findSpansForProfile's existing signature and behavior are unchanged for every existing caller; the new diagnostics are opt-in via a sibling function. -
8098aee: Persisted
codeReview/securityAuditfindings on aSUMMARY.jsonare now rendered in both Markdown summary surfaces — the on-disk<id>-SUMMARY.mdsidecar (renderSummaryMd) andcadence summary render's output (renderSummaryForReview) — under a shared## Findingssection, placed after## Tasksand before the gates heading in both. Previously these findings were JSON-only: a refused settle or a pasted PR summary gave no visibility into the finding that actually caused the refusal without opening the raw.jsonrecord.Findings are grouped and ordered deterministically:
codeReviewfindings by file path (codepoint order), then severity (critical > high > medium > low), thenid;securityAuditfindings by severity thenid, with original array order as the stable tie-break whenidis absent (as it always is forsecurity-auditfindings under the current schema). Each rendered line includes severity, message, and — when present — line, id, target, anchor (kind/ref/tier), disposition, and waiver expiry. The## Findingsheading itself is omitted entirely when there is nothing to render, so every historical summary predating this change (nocodeReview/securityAuditfields at all) renders byte-identically to before, andcadence summary verify'scontentHashcheck — which hashes the parsed JSON, never the Markdown — is unaffected; a new test sweeps all 269 existing.cadence/phases/**/*-SUMMARY.jsonrecords in this repo to prove it.Every rendered finding message passes through the existing
redactSecretsutility.security-auditfindings were already redacted upstream before reachingSummaryZ; this adds the same protection forcode-reviewfindings, which previously were not. Only the credential shapesredactSecretsalready recognizes (PEM keys, JWTs, AWS access keys, GitHub tokens, Authorization headers,key=/token=/password=/secret=-style assignments) are redacted — webhook URLs and bare local file paths are not, and are deliberately out of scope; wideningredactSecrets's shared patterns (it also backsgates/security-audit.ts,intelligence/finding-routing.ts, and others) is left to a future phase if ever needed. -
a5e729d: Added a new
cadence doctorcheck,roadmap-currency, that reports drift between the highest phase number under.cadence/phases/and the highest phase number referenced inROADMAP.md/MILESTONES.md— an anti-recurrence mechanism for the 113-phase/6-week ROADMAP drift fixed in PR #321.Drift is computed against the lower of the two reference files (using only files that contain at least one
Phase Nheading — a file with zero matches is excluded from the comparison, never treated as0, so a consumer repo that only maintains one of the two files doesn't warn forever).severity: 'warning'when drift exceeds 10 phases,'ok'otherwise, andfixId: nullalways — generating roadmap prose is deliberately not automated. The check silently passes on a fresh consumer repo (no phases yet, orROADMAP.mdstill theinitstub), and degrades to a best-effort "not determinable"okon any unexpected read failure rather than throwing.
Patch Changes
- @thomas-powers-jr/cadence-types@1.55.0
Published Packages
All public packages are published on npm as 1.55.0:
@thomas-powers-jr/cadence-core@thomas-powers-jr/cadence-host-claude-code@thomas-powers-jr/cadence-host-codex@thomas-powers-jr/cadence-host-toolkit@thomas-powers-jr/cadence-types
Verification
- npm publish completed with provenance in the Release workflow.
- Remote tag
v1.55.0is verified before the GitHub Release is created. - npm package versions and GitHub Release metadata are verified after publish.
- Workflow run: https://github.com/thomas-powers-jr/cadence/actions/runs/31215217214
v1.54.0
Package Changelog
Minor Changes
-
fcd76ad: Fixed a provenance-honesty gap: when a
code-revieworsecurity-audit
verifier throw (the call itself never returned — revoked key, network
blip) was bypassed via--force,--allow-code-review-failure, or
--allow-security-audit-failure, the persistedSUMMARY.gates[]entry
read{ gate: 'code-review', status: 'ran' }— indistinguishable from a
clean real-provider pass, since only the absence of the phase-232
provider/modelfields hinted anything was wrong.Both gates' catch blocks now set a new, distinct
GateFlags.reviewVerifierFailure
field on a bypassed throw (deliberately not the pre-existingverifierFailure
field, which is reserved fordeep-verifyand feedsnotify/collect.ts's
anomaly emission — reusing it would have fabricated a falsedeep-verify
entry inSUMMARY.gateBypasses).packages/core/src/gates/registry.ts's
runSettleGatesdispatch loop turns this into an honest
status: 'skipped'entry with askipReasonnaming the flag that
triggered the bypass, the underlying failure message, and the configured
provider — with no fabricatedprovider/modelstructured field, so the
entry correctly stays excluded fromderiveAssuranceRecord's
verifierRollup. The bypass also now prints a loud stderr notice, matching
this repo's no-quiet-fallback convention. A verifier throw with no bypass
flag set continues to refuse identically to before (exit code, exact
stderr reason text, and noflagson the refusal — all unchanged).Out of scope, unchanged: the pre-existing findings-based bypass path (real
HIGH/CRITICAL findings waved through on a review call that did return)
still correctly recordsstatus: 'ran'with a realverifierIdentity.
deep-verify.ts's own identical registry-side gap (its bypassed throw also
still recordsstatus: 'ran'with empty identity today) is a separate,
unscoped concern — tracked as a follow-up recommendation. -
8b42ff4: Renamed the npm scope to
@thomas-powers-jracross all five published
packages, matching the GitHub org rename in #360. This is a rename of
existing software on its existing 1.x version lineage, not a new product —
consistent with the standing pre-v2.0.0 semver policy.The previously-published packages under the old scope are not deleted —
they stay resolvable and getnpm deprecated with a pointer to the new
scope, as a separate operator-run step after this release. See
docs/migration-npm-scope.md for the full
migration path, including the exactcadence doctor --fix --wire-host
command that repairs an existing consumer's host-adapter hook install.cadence doctor's host-hooks andcadence config explain's warnings both
now distinguish a hook entry that's missing entirely from one that's
present but still pointing at the old scope — previously both cases
reported the same "not found" message, which was factually wrong for the
second case. -
8f58bde: Fixed three more silent-refusal gaps in
cadence settle run: the
AC-derivation refusal (--auto/--interactivefinding a blocked or
incomplete task), the anomaly/skill-audit refusal, and the evidence-floor
refusal each previously exited 1 with zero durable evidence beyond an
ephemeral stderr line — noSUMMARY.json/.mdwas written at all. Phase
247 had already fixed this for the gate-loop refusal family (a gate itself
returningrefused); these three post-gate-loop families were a separate,
undocumented gap in the same mechanism.All three now route through the existing
writeRefusedSettleSummary
(unchanged), reusing theacc/gatesalready computed earlier in
settleService— no new parameters on any helper function, no
reimplementation. A findings-bearing refusal in any of these three
families inherits the identical conditionalcontentHashand per-attempt
snapshot-sibling behavior phase 247 built for the gate-loop family;
acResultsstays[]on all four refusal families alike, matching the
existing invariant. Exit code, stderr messaging, loop-state non-mutation,
and every gate's own outcome are unchanged.Out of scope, unchanged by design:
loadSettlePreconditions's precondition
refusal,checkPhaseCollisionBackstop's worktree-collision backstop, and
resolveSettleGateSet's soft-cap refusal all fire before agates
provenance array exists to attach a SUMMARY to — none of the three writes
one, before or after this change. -
afcb90a: Fixed two compounding data-loss gaps in a refused (failed)
cadence settle:
writeRefusedSettleSummary(packages/core/src/services/settle.ts) never
recorded thecodeReview/securityAuditfindings that caused the refusal
in the first place, even though they were already accumulated intoacc
by the time the gate loop halted — they were computed, then silently
dropped at the write. Fixed by threadingacc.codeReview/
acc.securityAuditinto the refusedSUMMARY.json, mirroring the
success path's shape exactly, with acontentHashattached exactly when
at least one of those collections is non-empty (a findings-free refusal —
e.g. a barebuild-test-must-passrefusal — keeps producing byte-identical
output to before this change).Second, even once recorded, a later settle attempt for the same draft
silently overwrote the previous attempt's refused record — a convergence
reloop's attempt-1 findings vanished the moment attempt-2 ran, success or
refusal. Fixed by additively writing an immutable per-attempt sibling pair
(<id>-refused-<completedAt-slug>-SUMMARY-snapshot.json/.md, exported as
refusedSnapshotArtifactBase) whenever a refusal recorded findings — named
so it is invisible to every existing SUMMARY-discovery consumer
(mcp/resources.ts,git/diff-strict.ts,verify phase,summary render/verify) by construction, best-effort (a sibling-write failure is
reported on stderr but never affects the canonical write or settle's exit
code), and never written on the success path or for a findings-free
refusal. The canonical<id>-SUMMARY.json/.mdcontinues to reflect only
the latest attempt, as before — nothing that reads it changes behavior;
prior attempts' siblings simply keep accumulating on disk.cadence summary verify'sNO_HASHoutcome andpackages/core/src/ services/summary-verify.ts's doc comment are updated to reflect the new
conditional truth:NO_HASHnow means "pre-phase-223 record, or a refused
settle that recorded no findings" rather than "any refused settle."
Patch Changes
- Updated dependencies [8b42ff4]
- @thomas-powers-jr/cadence-types@1.54.0
Published Packages
All public packages are published on npm as 1.54.0:
@thomas-powers-jr/cadence-core@thomas-powers-jr/cadence-host-claude-code@thomas-powers-jr/cadence-host-codex@thomas-powers-jr/cadence-host-toolkit@thomas-powers-jr/cadence-types
Verification
- npm publish completed with provenance in the Release workflow.
- Remote tag
v1.54.0is verified before the GitHub Release is created. - npm package versions and GitHub Release metadata are verified after publish.
- Workflow run: https://github.com/thomas-powers-jr/cadence/actions/runs/30771173624
v1.53.0
Package Changelog
Minor Changes
-
eddfc6b: The anchor ladder's
executabletier is now reachable in a real settle (Phase
241,rec-20260729-002/rec-20260729-007). Phase 235 shipped the full
four-tier ladder as a pure resolver, but its top rung was dead in production:
SettleContextexposed no prior-gate provenance to aGateImpl— the
accumulator was a local insiderunSettleGates— sogates/code-review.ts
called the resolver with a literal[]and every live finding capped at
structured/declared/undeclared.executablewas exercised only by unit
tests that injected provenance directly.SettleContextgains an optional, readonlygateProvenance— the entries
recorded so far this settle, inGATE_ORDER.runSettleGateshands each
gate a per-gate context carrying a two-level-frozen snapshot: the array
and each entry are frozen, and the entries are copies. The element-level
freeze is the load-bearing half — a shallow copy would leave entries sharing
object identity with the live accumulator, so a gate could have rewritten an
entry that lands inSUMMARY.json.gatesand feeds the phase-233 assurance
record. The field is typedreadonly Readonly<GateProvenance>[], so the
compiler refuses element mutation and the runtime copy holds even against a
gate that casts the guard away. (A plainreadonly T[]would not suffice: it
constrains the array's shape, not its elements' fields.)- The field is optional and additive: every pre-existing
SettleContext
literal, in production and in tests, compiles unchanged, and a reader treats
an absent field the same as an empty array — never as "unknown". gates/code-review.tspasses that snapshot through. Becausecode-review
runs 9th inGATE_ORDERandbuild-test-must-pass5th, the corroborating
status is already recorded by the time anchoring happens.
This widens what is reachable without weakening what must be earned.
The ladder's two-condition check inverify/anchor.tsis untouched:
executablestill requires both an AC cited by a task with a non-empty
verify:and abuild-test-must-passentry withstatus: 'ran'. A
skipped,refused, or absent entry still caps the tier — a failing suite
waved through with--allow-failing-buildrecordsskippedand demonstrably
cannot buy a stronger anchor.Reachability is proven end-to-end rather than asserted: a new test drives the
real CLI over an ephemeral repo at a profile whose gate set includes
code-reviewand reads the tier back out of the persistedSUMMARY.json.
Reverting the one-line gate change flips that recorded tier fromexecutable
tostructured, so the test measures the production path and nothing else.Two limitations disclosed with the ladder in phase 235 remain open and are
still documented: anchoring is resolved per-file rather than per-finding, so an
uncovered defect in an otherwise-covered file can be missed
(rec-20260729-003); and a boundary string that merely contains a finding's
filename as a substring can mask a real gap by grantingdeclaredtier too
broadly (rec-20260729-005). -
c27bcb0:
code-reviewfindings are now criteria-anchored (Phase 235,rec-20260727-004
/rec-20260727-005): every finding is tagged with how strongly it ties back
to something the phase's DRAFT actually declared, on a four-tier ladder —
executable>structured>declared>undeclared— resolved by a new
pureresolveAnchor(packages/core/src/verify/anchor.ts). A finding whose
best anchor resolves toundeclaredis a criteria gap: diff work no
acceptance criterion and no boundary covers.GateProvenanceZ-adjacentSummaryZgains an additiveAnchorZpeer schema
({ kind: 'ac' | 'boundary' | 'none', ref?, tier }, deliberately independent
of the existingAcEvidenceZladder — the two rank different things) and
FindingZgains an optionalanchorfield. Both are purely additive: a
pre-phase-235SUMMARY.jsonwith noanchoron any finding still parses
unchanged.A criteria gap adds no new refusal path and no new bypass flag — a gap
finding flows into the exact same finding streamcode-reviewalready
refuses on, so a HIGH-severity gap refuses through the pre-existing
HIGH-finding contract (dec-20260729-005); gap count and severity
distribution are declared to stderr unconditionally, independent of whether
the gate passes, refuses, or is bypassed (dec-20260729-006).GATE_ORDER
and every gate's pass/refuse semantics for pre-existing finding classes are
unchanged. Scope is deliberately narrow — onlycode-reviewis
criteria-anchored;spec-review,ui-spec-review, andplan-revieware
untouched (dec-20260729-003).Three limitations were filed rather than papered over. The first —
executablenot being reachable in a real settle, becauseSettleContext
exposed no prior-gate provenance to a single gate (rec-20260729-002) — is
resolved by phase 241 in this same release, so it never reaches a
published version; see that entry for the fix. The other two remain open:
anchoring is resolved per-file rather than per-finding, so an uncovered
defect in an otherwise-covered file can be missed (rec-20260729-003); and a
boundary string that merely contains a finding's filename as a substring can
mask a real gap by grantingdeclaredtier too broadly (rec-20260729-005). -
5cc4085: Findings now carry a stable identity (Phase 236,
rec-20260727-006):FindingZ
gains additiveid,target: 'artifact' | 'verification',disposition: 'open' | 'accepted' | 'waived' | 'fixed' | 'superseded', andwaiver: { expiry }
fields.idis a pure content hash over(file, normalized message)—
deliberately never a line number, so the same finding keeps the sameid
across settles even after an unrelated edit shifts which line it sits on
(packages/core/src/verify/finding-identity.ts).anchor/severityare
accepted as parameters for call-site compatibility but do not participate in
the hash (Phase 245 narrowed the formula from an original(file, anchor.kind, anchor.ref, severity, normalized message), after independent review found
both anchor and severity can legitimately change across settles for the same
underlying defect). A
waiveris only valid whendisposition === 'waived', enforced by a
cross-field schema refine — a waiver with no expiry is a belief masquerading
as knowledge, and an orphaned waiver on a non-waived finding is never valid.
AnchorZ.kindwidens to also accept'invariant', unused by any producer yet
(a follow-on phase's scope).The
code-reviewverifier's persisted findings (gates/code-review.ts) now
carry this identity:id,target: 'artifact', and a default
disposition: 'open', alongside their existing §7.1 anchor tag. This required
converging code-review's previously-local 3-severityFinding/FindingSeverity
type onto the shared, persisted 4-severityFindingfrom@manehorizons/cadence-types
(rec-20260727-006's design-doc decision D9 — "oneFindingtype,
discriminated bytarget").CodeReviewFinding/CodeReviewFindingSeverity
remain available frompackages/core/src/contracts/index.tsas backward-compat
aliases of the now-shared type —CodeReviewFindingSeveritycorrespondingly
widens from'high' | 'medium' | 'low'to the full'critical' | 'high' | 'medium' | 'low'union, though no code-review provider constructs'critical'
today.RecommendationSourceZgains a'review'member (rec-20260727-011), so a
future phase that routes code-review findings into the recommendation ledger
can carry real provenance instead of mislabeling themmanual/cadence.All schema changes are purely additive — every pre-phase-236
SUMMARY.json
still parses unchanged. This phase is deliberately schema-and-computation
only: findings-to-ledger auto-routing (creatingRecommendation+Evidence
entries from findings during settle) is not implemented here — that
behavioral work is split to a follow-on phase, recorded inline in
.cadence/ROADMAP.md's Phase 236 entry. -
7ddc72a: Identified code-review findings now route into the recommendation ledger at
settle time (Phase 242,rec-20260731-003) — the behavioral half Phase 236
deliberately deferred. Each finding that carries a stableFinding.id(Phase
236 identity) becomes aRecommendationwithsource: 'review', linked to a
cadence-artifactEvidenceentry whosepathis that settle's
<draftId>-SUMMARY.jsonand whosesummarynames the phase id, draft id, and
SUMMARYcontentHash. Routing is keyed onFinding.id, so a re-settle of an
unchanged phase never mints a duplicate entry for a finding already routed,
and one freshly-mintedscoutIdcovers a whole settle's batch rather than one
per finding. Findings with no stable id (e.g.security-audit, which has no
identity wired in yet) are skipped, never force-routed.RecommendationZgains an optionalsourceFindingId(the dedup key), and
addRecommendationgains optionalsourceand a structuredcadence-artifact
evidence override — both backward compatible; every existing caller keeps
today'ssource: 'manual', free-text-evidence behavior unchanged. Two or more
findings that collide on identity within one settle (rec-20260731-001's
known collision — same file/anchor/severity/normalized-message, no occurrence
discriminant) merge into a singleRecommendationrather than mint one entry
with no trace of the duplicates or N separate entries for one id; per
dec-20260731-001, the identity hash itself is untouched — the merge records
the occurrence count explicitly in the entry's evidence/summary text.A new
recommendations.autoRouteconfig field (boolean, def...
v1.52.0
Package Changelog
Minor Changes
-
a58cac1: Closed three drifts around
gates.sealed(rec-20260725-006). Docs now name all
three gates that actually consultisGateSealed(test-coverage,
build-test-must-pass,boundary-scan—docs/reference/config.mdand
docs/concepts.mdpreviously named only the first two, stale since
boundary-scanshipped in Phase 156), plus the missing--allow-failing-build
/--allow-boundary-scan-failurerows in the "Gate bypass reference summary"
table; a new doc-content test derives the sealed-gate set from the real
isGateSealedcall sites so a future gate can't drift the same way again.
docs/concepts.mdgains a "Bypass-flag naming policy" section explaining the
--force/--allow-<gate>-failure/--allow-<verb>split and auditing
every bypassable gate's flag against it.runSettleGates's gate-provenance
collection now records a bypass-specific skip reason forbuild-test-must-pass
andboundary-scan(previously onlytest-coverage's bypass was distinguished
from a normal "ran"), naming whichever flag actually fired (--forcevs the
gate's own dedicated flag) rather than always naming the dedicated one. No
gate pass/refuse/seal decisions changed — this is documentation accuracy and
provenance-recording parity only. -
90e3ed9: Closed the phase-attributable AC coverage collision (phase 239). Nothing in a
settled phase's artifacts previously recorded which phase a test belonged to:
thetest-coveragegate searched everypackages/**/*.test.tsfor the bare
AC-Ntoken, so any past phase'sAC-3satisfied every future phase's
AC-3(AC ids restart atAC-1every phase);
meanwhilecadence verify phase's replay scoped its re-scan to only the files
the DRAFT declared, which chronically under-declares and produced false
"drifted" verdicts against phases whose tests genuinely still pass.A new opt-in
verification.coverageSchemeconfig field ("bare"|"phase-qualified",
schema default"bare") closes both. Under"phase-qualified", anAC-N
token must carry its phase-slice prefix (239-01/AC-3) to count as coverage
evidence — a bare or foreign-phase token no longer satisfies the gate, and
every refusal names the exact expected token.cadence verify phasedrops
file-scoping entirely for a phase-qualified SUMMARY and instead matches by
that phase's own qualified token across the configuredverification.testGlobs,
so an under-declared DRAFT no longer produces false drift. A phase
settled before the scheme existed has no phase-attributable evidence at all;
its replay now reports every ACindeterminatewithdrift: falserather
than asserting a verdict it cannot substantiate.The field defaults to
"bare"for every existing config (including one that
predates this field) — this is a two-layer default:defaultConfigitself
holds"bare"soloadConfig's config.json-over-defaultConfigmerge never
silently flips an upgraded consumer, and only a freshcadence initwrites
"phase-qualified"explicitly. Existing consumers on@manehorizons/cadence-core@1.51.1
are fully unaffected until they opt in viacadence config edit coverageScheme.
SUMMARY.jsongains additive, optionalcoverageScheme/coverageModefields
recording which scheme produced a settle's evidence;cadence verify coverage --explainreports per-occurrence whether a token satisfies the configured
scheme. -
127a06b: BREAKING (engine floor): minimum supported Node.js raised from
>=20to
>=22. Node 20 reaches its scheduled end-of-life in April 2026, and Phase
238 retires the Node 20 CI/test leg across the monorepo (see
.cadence/phases/238-drop-node20-support/) — these packages are no longer
tested against, or guaranteed to work on, Node 20 or 21. Shipped as a minor
bump rather than major, matching the precedent set by the Zod v3→v4 upgrade
([1.4.0]): no external adopters are affected at release time, and CADENCE
is reserving its first major/2.0.0 release for when the full coupling of
Cadence is complete.Every published package's
package.jsonnow declares
"engines": { "node": ">=22" }. Consumers still on Node 20 or 21 should
upgrade their Node.js runtime before installing or running any package at
this version or later — by default, npm and pnpm only warn on an
enginesmismatch (this repo does not setengine-strict), but CI
pipelines or environments withengine-strictenabled will fail outright,
and pipelines pinned to Node 20 should bump their Node version to keep
using thecadenceCLI, either host adapter, or
@manehorizons/cadence-types. -
92ae02e:
cadence doctorgains aledger-remote-collisioncheck (rec-20260726-003):
mintIdcomputes the next recommendation/evidence/decision/assumption id
purely from the local ledger on disk, so two unpushed branches/worktrees/
sessions can independently mint the same id for different content — this
happened for real on 2026-07-26 and required a manual git-merge + JSON-union
fix (PR #308).The new check fetches the tracked upstream branch (reusing the existing
checkRemoteFreshnessfetch plumbing), resolvesgit merge-base HEAD @{u},
and diffs local's new-since-merge-base ledger ids against the upstream's
new-since-merge-base ids across all four ledgers, warning (nevererror) on
any overlap and naming the colliding id(s). It degrades safely took— no
git repository, no upstream, a failed fetch, a detached HEAD, or no
discoverable merge-base all skip the check rather than failing it. No
--fixauto-repair exists for this finding — resolving a real collision
needs a human to pick which side re-mints, matchingworktree-phases. -
d7d4239:
SUMMARY.jsongets a settle-time content hash, closing the "hand-edited
SUMMARY renders faithfully as if it were genuine" gap (rec-20260724-006).Summary(types) gains an optional, additivecontentHash: { algorithm: 'sha256'; value: string }field — existing SUMMARY.json records without
it keep parsing unchanged.cadence settle runnow computes a sha256 digest over a canonical
(deep, stable-key-order) stringification of the settled summary and
attaches it before writingSUMMARY.json/SUMMARY.md. Bothcadence summary renderand the settle-timeSUMMARY.mdsidecar display it.- New
cadence summary verify <phase> <num>recomputes the digest and
reportsMATCH,MISMATCH(non-zero exit — the stored hash doesn't
match the content, i.e. the file was edited after settle), orNO_HASH
(a pre-phase-223 or refused-settle record, reported cleanly rather than
a false pass).
This is detection only, not signing — self-signing in the same trust
domain as the artifact's author isn't meaningfully stronger than a hash.
Full cryptographic signing with an external trust root is deferred to
rec-20260726-001, gated on the parked MCP/hooks/host-adapter/verifier/
ledger threat-model rec (mil-rec-rec-20260712-016). See dec-20260726-001
for the full rationale.
Patch Changes
-
f88716c: Fixes rec-20260726-002: a fresh
EnterWorktreegit worktree (or a fresh
clone) carries the committed.cadence/scaffold but neverstate.json
(gitignored since phase 196), so every state-mutating command threw
NotInitializedErrorsaying "runcadence init" — butcadence init
correctly refuses on an already-.cadence/-committed repo, a dead end that
had to be worked around by hand-authoringstate.json(hit live during
phase 222).cadence onboardalready bootstraps exactly this case safely
(phase 196 fallout, #177), but nothing in the failure path pointed at it.
SimpleStateBackend.readState()'sNotInitializedErrornow distinguishes
".cadence/doesn't exist at all" (still namescadence init) from
".cadence/exists butstate.jsonis missing" (now namescadence onboard), andcadence init's "already initialized" refusal prints an
additional line pointing atcadence onboardin the same missing-state.json
case.cadence initstill refuses and writes nothing either way — only the
guidance changes. -
0e854cd: Extracted a shared
runConvergentReviewprimitive (inpackages/core/src/verify/converge.ts,
alongsidenextConvergence) that all 4 bounded-convergence call sites
(plan-review,code-review,spec-approve's spec-review and ui-spec-review)
now delegate to, instead of each independently re-implementing the same
read-sidecar → verify → verdict → history-append → write-sidecar → branch
sequence (rec-20260725-008). Purely internal — no change to the convergence
policy, sidecar JSON on-disk shape, or CLI-visible behavior; a future fifth
convergence call site (e.g. survey #4's settle-gate convergence) can now reuse
this primitive instead of copy-pasting a fifth time. -
84dc9bd: Fixes #331:
cadence doctor'sverification-readinesscheck inspected only the
deep-verify seam despite its seven-seam name, so a seam configured to a real
provider whose credentials were absent was classified as real and never
credential-checked —doctorprinted✓ okwhile that gate was guaranteed to
silently fall back tomockat call time.cadence config explainalready
caught this via itsprovider-no-keywarning, and its remedy line says "Run
cadence doctorto confirm provider health" — pointing the operator at the
command that reported the green tick.assessReadinessgainsseamsDowngraded: the seams whose configured provider
is real but whose credentials are missing, inVERIFIER_SEAMSorder. It never
includes amockseam (not a downgrade — it announces itself) nor ahost-cli
seam (no required credential by design). The existingseamsReal/seamsMock
partition, which classifies by configured provider name, is unchanged — the new
field expresses what that partition structura...
v1.51.1
Package Changelog
Patch Changes
-
e9f6556: Closes three confirmed CLI/MCP parity gaps in the Praxis-adjacent surfaces:
cadence_recommendation_promote(MCP) now accepts arefargument and
threads it intoshippedRefexactly like the CLI's
recommendation promote --status=shipped --ref "<text>"already does —
previously the MCP tool silently dropped it. Also fixes a latent bug where
astatus=shippedpromotion (which auto-archives by default) always
returneddata: nulleven on full success, because the lookup only
checked the liverecommendationsarray, notarchived.- The "did this
milestone proposerun produce any newly-proposed
milestones" predicate — previously copy-pasted as an identical literal
expression in bothcli/commands/milestone.tsand
services/milestone-propose.ts, a duplication class that had already
caused one whole-branch-review-caught drift bug — is now a single
exportedhasNewlyProposedMilestone()both call sites invoke. next/verify coverage/verify phase/explainlogic, which already had
the right(repoRoot, args, io) => CommandResultservice shape but lived
incli/commands/where the MCP surface couldn't reach it, is relocated
intoservices/{next,verify,explain}.ts. The MCP server now registers
cadence_next,cadence_verify_coverage,cadence_verify_phase, and
cadence_explain(all read-only), with test coverage asserting output
parity against their CLI counterparts.docs/mcp.mdand
docs/reference/commands.mdare updated for the new tool count (18→22).
No CLI-facing behavior, flags, or exit codes changed for any of the affected
commands — this is a parity/dedup fix, not a rewrite. -
655663e: Unify the five Praxis intelligence ledgers (recommendations, evidence,
assumptions, decisions, milestones) onto one shared read/write/id-minting
module (intelligence/store/ledger.ts) instead of five independently
hand-rolled implementations, so a safeguard added for one subject — like
phase 219's cross-ledger id-collision check, previously recommendations-only
— now applies to all four minting subjects (recommendations, evidence,
assumptions, decisions) instead of needing to be re-patched per subject.
Each subject's existing read/write/mint function names and signatures are
unchanged (thin wrappers over the shared primitives); bespoke per-subject
logic (recommendation promotion/archive/unarchive, decision supersession)
stays subject-specific rather than being forced into one generic shape.Also fixes a real gap this refactor surfaced:
milestones.jsonwas the only
one of the five ledger files not written with{ mode: 0o600 }.cadence intelligence audit/reconcile/statsnow include milestones as a
fifth ledger: a neworphan-milestonefinding kind catches a milestone
referencing a recommendation id that no longer exists in either the live or
archived recommendation arrays (a reference to a merely-archived, still
unarchive-recoverable recommendation is correctly NOT flagged).cadence recommendation/decision/assumption list's--sort-by/
--filter-regex/--filter-regex-flagsvalidation is now one shared
pipeline instead of three independently maintained copies — behavior and
error wording are unchanged.cadence-types,cadence-host-claude-code, andcadence-host-codexcarry
version-alignment bumps only; none of the three changed. -
e05922e: Fix
cadence recommendation add's id-minting to cross-checkevidence.json
(phase 219, rec-20260724-013).nextRecommendationIdpreviously derived the
nextrec-YYYYMMDD-NNNid only fromrecommendations.json, so a dangling
evidence.jsonrow left behind by a bad rebase-conflict resolution or an
interruptedaddcall — arecommendationIdreference with no matching
recommendations.jsonentry — could silently collide with a freshly minted
id for an unrelated recommendation. The minted id is now guaranteed strictly
greater than both therecommendations.jsonmax and the max
recommendationIdreferenced byevidence.jsonfor the same date prefix.Also adds a new
orphaned-evidencecadence doctorcheck that surfaces any
evidence.jsonrow whoserecommendationIdhas no matching
recommendations.jsonentry, naming the evidence id and the missing
recommendation id — so this class of drift is caught immediately instead of
surviving unnoticed.cadence-types,cadence-host-claude-code, andcadence-host-codexcarry
version-alignment bumps only; none of the three changed. -
1f70e66: Extracts the logic host-claude-code and host-codex duplicated into a new
shared package,@manehorizons/cadence-host-toolkit:- The hook-event routing algorithm's shape and the slash-command catalog
(COMMANDS) now live inhost-toolkit/src/routing.ts. Both adapters
render their slash commands from this one catalog, which fixes a real
drift bug: host-codex's local copy had silently lostcadence-dispatch's
DISPATCH_DIALOGUEbody. Host-codex's ownmapEvent/extractPayload/
routeHookEventstay local — itsapply_patch-based extraction is
genuinely different from host-claude-code'sfile_path-based extraction,
not just duplicated; only the structurally-identicalRouteResulttype is
shared. install.ts's managed-marker merge logic andlocate-self.tsare also
extracted into the toolkit, with one shared test suite; both adapters'
owninstall.ts/locate-self.tsare now thin wrappers.- Core now enforces a new
HostCapabilities.agentIdentificationflag: a
host that declares it cannot supplyagentId/agentType(Codex, whose
hook payload shape doesn't document one) causes core to notice loudly on
stderr instead of silently behaving as if no subagent were involved.
Codex's CLI now embeds its declared capabilities into the real hook
payload it sends tocadence hook, so the check is live end-to-end, not
just testable in isolation.
No CLI-facing behavior, flags, or exit codes changed for either adapter —
this is an internal dedup/extraction plus one new loud-notice-on-a-capability-
gap fix, not a rewrite.HostAdapter's public contract is unchanged. - The hook-event routing algorithm's shape and the slash-command catalog
-
Updated dependencies [655663e]
-
Updated dependencies [e05922e]
-
Updated dependencies [1f70e66]
- @manehorizons/cadence-types@1.51.1
Published Packages
All public packages are published on npm as 1.51.1:
@manehorizons/cadence-core@manehorizons/cadence-host-claude-code@manehorizons/cadence-host-codex@manehorizons/cadence-host-toolkit@manehorizons/cadence-types
Verification
- npm publish completed with provenance in the Release workflow.
- Remote tag
v1.51.1is verified before the GitHub Release is created. - npm package versions and GitHub Release metadata are verified after publish.
- Workflow run: https://github.com/manehorizons/cadence/actions/runs/30183850587