Skip to content

Releases: thomas-powers-jr/cadence

v1.60.0

Choose a tag to compare

@github-actions github-actions released this 15 Aug 21:20
e51e223

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, and cadence draft check warns (never blocks) when a task declares files: with no stop:. cadence build task <id> --status=DONE now runs a boundary + redundancy check at record time from real git diffs rather than agent self-report: a stray file outside the task's declared files: refuses the recording (exit 1, no mutation) once boundaryEnforcement resolves to block, unless --allow-boundary-breach is passed (records anyway, emits an error-severity anomaly). Independent of that config field, one task recorded with --execution dispatch escalates boundary enforcement to block for the rest of the phase and never de-escalates. --isolation and --model-class round out the new recording flags; all three carry through to SUMMARY.json on settle when present. Fully additive: no schemaVersion bump, no .default() on any new field, and the existing settle-time boundary-scan gate is unchanged.
  • 06d8790: cadence dispatch plan now computes an advisory execution verdict per task — { execution: 'inline'|'dispatch', modelClass, model, reasons[] } — giving config.subagentPolicy and config.modelPerClass their first consumer. A new optional class: 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 a cadence draft check coherence warning. --json output gains the new per-task fields plus a top-level signals.contextUtilization (always null for 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: no schemaVersion bump, no change to existing fields, and dispatch plan remains 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

v1.59.0

Choose a tag to compare

@github-actions github-actions released this 14 Aug 23:18
8dfd395

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. --keep leaves the playground on disk, --in-place runs inside the current directory (refusing loudly instead of overwriting an existing .cadence/ there), --interactive/-i opts into the tutorial's TTY-paced pauses. A bare npx @thomas-powers-jr/cadence-core or bare cadence invocation now dispatches straight into it. cadence tutorial keeps working unchanged, with one added stderr line pointing at cadence 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 successful cadence demo run advances to at least Driver. cadence help and cadence start now hide doctor below stage 2; a new top-level --advanced flag 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 (on recommendation 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 CodeQL js/regex-injection (ReDoS) finding on packages/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

v1.58.0

Choose a tag to compare

@github-actions github-actions released this 14 Aug 04:18
edbd2fd

Package Changelog

Minor Changes

  • 85fc5d2: Added a new cadence doctor check, recommendation-archive-currency, that warns when a recommendation in the active recommendations[] array carries a terminal shipped/rejected status without being moved into the archived[] 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 at cadence recommendation archive <id>.

    converted and settle-pending are deliberately excluded from the flagged-status set: a converted recommendation's only schema-documented successor state is settle-pending (reached solely via the settle hook), not archived, so flagging it would emit wrong remediation.

    Diverging from the two adjacent ledger-reading doctor checks (recommendation-shipped-drift, orphaned-evidence), a malformed/schema-invalid recommendations.json reports indeterminate, never a silent best-effort ok — a genuinely missing file still reports ok (the normal fresh-repo state). fixId is always null: archiving is evidence-gated per record, not a safe blind auto-repair, so --fix never 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

v1.57.0

Choose a tag to compare

@github-actions github-actions released this 13 Aug 23:43
07b912b

Package Changelog

Minor Changes

  • c582da3: deep-verify and per-task-verify now persist the provider/model identity that actually ran them into a settle's gates[] array — previously neither gate recorded any identity there at all (unlike code-review/security-audit), so an operator reading SUMMARY.json had no way to tell whether either had run under a real verifier or the mock placeholder.

    The new fields — observedProvider, observedModel, and (for per-task-verify) taskId — are structurally separate from the existing provider/model fields on GateProvenanceZ, so deriveAssuranceRecord's assurance rollup, which folds gates[].provider/.model by field name, stays completely blind to them. This is deliberate: this repo's own verifiers already run as host-cli (non-mock), so naively feeding deep-verify's and per-task-verify's identity into the existing rollup fields would silently inflate assurance.overall toward strong on 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-verify never previously appeared in gates[] at all — it runs during BUILD, not settle. Settle now synthesizes one entry per task carrying a persisted PerTaskVerifyRecord, 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 in gates[] is the gate that most recently ran or refused during this settle).

    All three new fields are additive and .optional() with no default and no schemaVersion bump — absent on every historical SUMMARY.json, and computeSummaryContentHash is unaffected.

  • 4901a00: cadence resume now warns when state.json's session.lastHandoff pointer names a SESSION-*.md file that no longer exists. Previously locateFreshestHandoff silently fell back to the freshest-by-generated_at doc 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 the cadence resume CLI text surface and the resumeService/MCP CommandIO surface.

    ResumeResult (@thomas-powers-jr/cadence-types) gains an additive, optional danglingHandoffPointer field 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 --deep no longer refuses (or requires --force) on an Acceptance Criterion whose satisfaction condition is structurally circular — it depends on the very SUMMARY.md/SUMMARY.json that 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 distinct unobservable verdict instead of an ordinary fail. unobservable-marked ACs are excluded from deep-verify's offenders list, the evidence-floor gate, and the force-used honesty report's deep: bucket — but never rolled up as a pass, and never allowed to move assurance.overall toward strong. SUMMARY.md and 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, optional unobservable boolean field. Absent on every historical SUMMARY.json and on every AC this classifier doesn't flag; computeSummaryContentHash is unaffected. The classifier defaults to observable on any ambiguity — a false negative is just an ordinary fail, while a false positive would silently excuse a real failure, so every trigger pattern is narrow and structural (case-sensitive SUMMARY token, 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

v1.56.0

Choose a tag to compare

@github-actions github-actions released this 11 Aug 22:57
01c09b3

Package Changelog

Minor Changes

  • 79a760a: cadence init now presents the verifier-provider choice explicitly: unless an explicit --verifier-provider <mock|anthropic|local|host-cli> flag, --activate, or --full already settled it, init asks which provider should back deep-verify — with mock listed 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, or CADENCE_PROMPTER_SCRIPT for scripted/CI runs); with no prompter available it silently defaults to mock — 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 via cadence decision list), so no repo runs indefinitely under an inherited default without the operator having made or seen that choice. --dry-run continues 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.json under .cadence/phases/** and verifies each one the same way summary 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 verify sweep 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-invoke FIFO-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 doctor check, conduction-drift-streak, that answers the trend question phase 251's conduction-reachability couldn'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.json corpus in chronological order and counting the consecutive most-recent settles that carried no non-mock provider identity in assurance.verifierRollup — the same drift that let 263 settles accumulate under mock with zero escalation, per the v1.54 audit. Also surfaced (without escalation) in cadence status.

    DoctorSeverity gains 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 from ok's "assessed, no problem found." Every existing consumer (DoctorReport.ok's roll-up, the fail() helper, cadence doctor --fix's fix-planner, the CLI/JSON renderer, doctorNextStep's Next-step guidance, and the MCP doctorService seam) handles it explicitly — indeterminate rolls up like warning (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 ok to warning — a warning only, never a settle refusal. That threshold is explicitly provisional (borrowed from an unrelated decision's config.convergence.maxAttempts default 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 doctor check, 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 a package.json engines bump landed on main but 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's engines field against npm's published engines for that package (npm view <pkg> engines --json), and independently flags any pending .changeset/*.md files awaiting release, naming each one's bump type (when reported on its own, wording escalates if any pending changeset declares a major or minor bump). Both signals fold into a single warning-severity finding (never error) with fixId: 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.json is missing, unparseable, or private: true, the whole check is skipped with a silent ok. If the npm view fetch fails — no network, an unpublished/private package, or a timeout — only the engines comparison is skipped; the pending-changesets signal is still evaluated. It never throws and never fails the cadence doctor exit code on its own.

  • 3e6019f: Added a new read-only diagnostic, cadence verify historical-coverage-audit, that audits every pre-phase-239 (coverageScheme absent) SUMMARY.json record's recorded AC PASS for genuine, attributable test evidence — answering rec-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), and unreachable (no literal, existing test file declared at all). It never performs a repo-wide bare-AC-N token scan (395 of 448 test files in a real corpus can contain that token as unrelated fixture data) and never resolves wildcard-glob files: entries. Purely additive and read-only: cadence verify phase's existing indeterminate contract and command path are unmodified.

    --json emits the full per-phase report; human mode prints aggregate bucket totals and an unreadable-record count. Exit code is always 0 on a successful run (a diagnostic, not a gate) and 1 only if the audit itself fails to run.

  • a66c412: Mock no longer records a persisted pass for 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 added console.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-audit gate provenance records status: 'skipped' with a skipReason naming the abstention (instead of 'ran'), and plan-review/spec-review/ui-spec-review's convergence sidecar (*-PLAN-REVIEW.json/*-SPEC-REVIEW.json/*-UI-SPEC-REVIEW.json) gains a new optional mockAbstained: true field on the relevant history entry. A mock-served refuse (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-verify and per-task-verify are unaffected — they enforce real AC↔test linkage under mock and keep their existing pass/fail semantics unchanged.

    GateProvenanceZ/ConvergentReviewHistoryEntry gain no required fields and no schema-version bump — both additive, matching the phase 239/263 precedent; every historical SUMMARY.json and 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.json profile moves off auto to standard in this same release, closing a previously-deferred baseline-profile decision — mock abstention removes the false-confidence risk that baseline change would otherwise have carried. See docs/handoffs/HANDOFF-v1.56-verifier-honesty.md (Phase P) for the full design history.

  • ca61066: Added providerSelection to persisted gate provenance, distinguishing three previously-indistinguishable states behind a provider: 'mock' entry: a deliberately configured provider (including a deliberately configured mock), a silent fallback to mock (at selection time in `createVerifierFactory...

Read more

v1.55.0

Choose a tag to compare

@github-actions github-actions released this 07 Aug 20:25
fb84baa

Package Changelog

Minor Changes

  • c8333f8: Added a new cadence doctor check, conduction-reachability, that reports — separately for code-review and security-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 auto gate profile excludes both review gates from every tier, and the self-invocation guard forces a mock verifier fallback whenever cadence is already running inside a headless Claude Code session. A third, ordinary (non-safety-related) blocker can also apply: a gate's own provider config being set to 'mock'.

    The check evaluates three axes per gate — profile inclusion (gatesFor across 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 reports severity: 'warning' naming exactly which axis or axes block each gate, with fixId: 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 the DELTAS gate 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," and docs/providers.md now documents the exact operator procedure (a DRAFT-level profile: override, run from a real interactive terminal) to produce one when needed.

  • db8209f: Fixed a real coverage-scanner defect: the JS/TS test-coverage gate's classify() 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 corrupted findMatchingParenIndex'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 new LanguageSyntax.regexLiterals field (set only for the built-in js-ts profile — 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 --explain reports 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/securityAudit findings on a SUMMARY.json are now rendered in both Markdown summary surfaces — the on-disk <id>-SUMMARY.md sidecar (renderSummaryMd) and cadence summary render's output (renderSummaryForReview) — under a shared ## Findings section, placed after ## Tasks and 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 .json record.

    Findings are grouped and ordered deterministically: codeReview findings by file path (codepoint order), then severity (critical > high > medium > low), then id; securityAudit findings by severity then id, with original array order as the stable tie-break when id is absent (as it always is for security-audit findings 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 ## Findings heading itself is omitted entirely when there is nothing to render, so every historical summary predating this change (no codeReview/securityAudit fields at all) renders byte-identically to before, and cadence summary verify's contentHash check — which hashes the parsed JSON, never the Markdown — is unaffected; a new test sweeps all 269 existing .cadence/phases/**/*-SUMMARY.json records in this repo to prove it.

    Every rendered finding message passes through the existing redactSecrets utility. security-audit findings were already redacted upstream before reaching SummaryZ; this adds the same protection for code-review findings, which previously were not. Only the credential shapes redactSecrets already 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; widening redactSecrets's shared patterns (it also backs gates/security-audit.ts, intelligence/finding-routing.ts, and others) is left to a future phase if ever needed.

  • a5e729d: Added a new cadence doctor check, roadmap-currency, that reports drift between the highest phase number under .cadence/phases/ and the highest phase number referenced in ROADMAP.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 N heading — a file with zero matches is excluded from the comparison, never treated as 0, 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, and fixId: null always — generating roadmap prose is deliberately not automated. The check silently passes on a fresh consumer repo (no phases yet, or ROADMAP.md still the init stub), and degrades to a best-effort "not determinable" ok on 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

v1.54.0

Choose a tag to compare

@github-actions github-actions released this 02 Aug 23:03
c71c12d

Package Changelog

Minor Changes

  • fcd76ad: Fixed a provenance-honesty gap: when a code-review or security-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 persisted SUMMARY.gates[] entry
    read { gate: 'code-review', status: 'ran' } — indistinguishable from a
    clean real-provider pass, since only the absence of the phase-232
    provider/model fields hinted anything was wrong.

    Both gates' catch blocks now set a new, distinct GateFlags.reviewVerifierFailure
    field on a bypassed throw (deliberately not the pre-existing verifierFailure
    field, which is reserved for deep-verify and feeds notify/collect.ts's
    anomaly emission — reusing it would have fabricated a false deep-verify
    entry in SUMMARY.gateBypasses). packages/core/src/gates/registry.ts's
    runSettleGates dispatch loop turns this into an honest
    status: 'skipped' entry with a skipReason naming the flag that
    triggered the bypass, the underlying failure message, and the configured
    provider — with no fabricated provider/model structured field, so the
    entry correctly stays excluded from deriveAssuranceRecord'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 no flags on 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 records status: 'ran' with a real verifierIdentity.
    deep-verify.ts's own identical registry-side gap (its bypassed throw also
    still records status: 'ran' with empty identity today) is a separate,
    unscoped concern — tracked as a follow-up recommendation.

  • 8b42ff4: Renamed the npm scope to @thomas-powers-jr across 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 get npm 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 exact cadence doctor --fix --wire-host
    command that repairs an existing consumer's host-adapter hook install.

    cadence doctor's host-hooks and cadence 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/--interactive finding 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 — no SUMMARY.json/.md was written at all. Phase
    247 had already fixed this for the gate-loop refusal family (a gate itself
    returning refused); 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 the acc/gates already 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 conditional contentHash and per-attempt
    snapshot-sibling behavior phase 247 built for the gate-loop family;
    acResults stays [] 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 a gates
    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 the codeReview/securityAudit findings that caused the refusal
    in the first place, even though they were already accumulated into acc
    by the time the gate loop halted — they were computed, then silently
    dropped at the write. Fixed by threading acc.codeReview/
    acc.securityAudit into the refused SUMMARY.json, mirroring the
    success path's shape exactly, with a contentHash attached exactly when
    at least one of those collections is non-empty (a findings-free refusal —
    e.g. a bare build-test-must-pass refusal — 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/.md continues 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's NO_HASH outcome and packages/core/src/ services/summary-verify.ts's doc comment are updated to reflect the new
    conditional truth: NO_HASH now 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

v1.53.0

Choose a tag to compare

@github-actions github-actions released this 01 Aug 22:01
16e6c8b

Package Changelog

Minor Changes

  • eddfc6b: The anchor ladder's executable tier 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:
    SettleContext exposed no prior-gate provenance to a GateImpl — the
    accumulator was a local inside runSettleGates — so gates/code-review.ts
    called the resolver with a literal [] and every live finding capped at
    structured/declared/undeclared. executable was exercised only by unit
    tests that injected provenance directly.

    • SettleContext gains an optional, readonly gateProvenance — the entries
      recorded so far this settle, in GATE_ORDER. runSettleGates hands 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 in SUMMARY.json.gates and feeds the phase-233 assurance
      record. The field is typed readonly Readonly<GateProvenance>[], so the
      compiler refuses element mutation and the runtime copy holds even against a
      gate that casts the guard away. (A plain readonly 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.ts passes that snapshot through. Because code-review
      runs 9th in GATE_ORDER and build-test-must-pass 5th, 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 in verify/anchor.ts is untouched:
    executable still requires both an AC cited by a task with a non-empty
    verify: and a build-test-must-pass entry with status: 'ran'. A
    skipped, refused, or absent entry still caps the tier — a failing suite
    waved through with --allow-failing-build records skipped and 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-review and reads the tier back out of the persisted SUMMARY.json.
    Reverting the one-line gate change flips that recorded tier from executable
    to structured, 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 granting declared tier too
    broadly (rec-20260729-005).

  • c27bcb0: code-review findings 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
    pure resolveAnchor (packages/core/src/verify/anchor.ts). A finding whose
    best anchor resolves to undeclared is a criteria gap: diff work no
    acceptance criterion and no boundary covers.

    GateProvenanceZ-adjacent SummaryZ gains an additive AnchorZ peer schema
    ({ kind: 'ac' | 'boundary' | 'none', ref?, tier }, deliberately independent
    of the existing AcEvidenceZ ladder — the two rank different things) and
    FindingZ gains an optional anchor field. Both are purely additive: a
    pre-phase-235 SUMMARY.json with no anchor on 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 stream code-review already
    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 — only code-review is
    criteria-anchored; spec-review, ui-spec-review, and plan-review are
    untouched (dec-20260729-003).

    Three limitations were filed rather than papered over. The first —
    executable not being reachable in a real settle, because SettleContext
    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 granting declared tier too broadly (rec-20260729-005).

  • 5cc4085: Findings now carry a stable identity (Phase 236, rec-20260727-006): FindingZ
    gains additive id, target: 'artifact' | 'verification', disposition: 'open' | 'accepted' | 'waived' | 'fixed' | 'superseded', and waiver: { expiry }
    fields. id is a pure content hash over (file, normalized message)
    deliberately never a line number, so the same finding keeps the same id
    across settles even after an unrelated edit shifts which line it sits on
    (packages/core/src/verify/finding-identity.ts). anchor/severity are
    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
    waiver is only valid when disposition === '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.kind widens to also accept 'invariant', unused by any producer yet
    (a follow-on phase's scope).

    The code-review verifier'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-severity Finding/FindingSeverity
    type onto the shared, persisted 4-severity Finding from @manehorizons/cadence-types
    (rec-20260727-006's design-doc decision D9 — "one Finding type,
    discriminated by target"). CodeReviewFinding/CodeReviewFindingSeverity
    remain available from packages/core/src/contracts/index.ts as backward-compat
    aliases of the now-shared type — CodeReviewFindingSeverity correspondingly
    widens from 'high' | 'medium' | 'low' to the full 'critical' | 'high' | 'medium' | 'low' union, though no code-review provider constructs 'critical'
    today.

    RecommendationSourceZ gains 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 them manual/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 (creating Recommendation + 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 stable Finding.id (Phase
    236 identity) becomes a Recommendation with source: 'review', linked to a
    cadence-artifact Evidence entry whose path is that settle's
    <draftId>-SUMMARY.json and whose summary names the phase id, draft id, and
    SUMMARY contentHash. Routing is keyed on Finding.id, so a re-settle of an
    unchanged phase never mints a duplicate entry for a finding already routed,
    and one freshly-minted scoutId covers 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.

    RecommendationZ gains an optional sourceFindingId (the dedup key), and
    addRecommendation gains optional source and a structured cadence-artifact
    evidence override — both backward compatible; every existing caller keeps
    today's source: '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 single Recommendation rather 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.autoRoute config field (boolean, def...

Read more

v1.52.0

Choose a tag to compare

@github-actions github-actions released this 31 Jul 14:46
c56532d

Package Changelog

Minor Changes

  • a58cac1: Closed three drifts around gates.sealed (rec-20260725-006). Docs now name all
    three gates that actually consult isGateSealed (test-coverage,
    build-test-must-pass, boundary-scandocs/reference/config.md and
    docs/concepts.md previously named only the first two, stale since
    boundary-scan shipped in Phase 156), plus the missing --allow-failing-build
    / --allow-boundary-scan-failure rows in the "Gate bypass reference summary"
    table; a new doc-content test derives the sealed-gate set from the real
    isGateSealed call sites so a future gate can't drift the same way again.
    docs/concepts.md gains 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 for build-test-must-pass
    and boundary-scan (previously only test-coverage's bypass was distinguished
    from a normal "ran"), naming whichever flag actually fired (--force vs 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:
    the test-coverage gate searched every packages/**/*.test.ts for the bare
    AC-N token, so any past phase's AC-3 satisfied every future phase's
    AC-3 (AC ids restart at AC-1 every phase);
    meanwhile cadence 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.coverageScheme config field ("bare" | "phase-qualified",
    schema default "bare") closes both. Under "phase-qualified", an AC-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 phase drops
    file-scoping entirely for a phase-qualified SUMMARY and instead matches by
    that phase's own qualified token across the configured verification.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 AC indeterminate with drift: false rather
    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: defaultConfig itself
    holds "bare" so loadConfig's config.json-over-defaultConfig merge never
    silently flips an upgraded consumer, and only a fresh cadence init writes
    "phase-qualified" explicitly. Existing consumers on @manehorizons/cadence-core@1.51.1
    are fully unaffected until they opt in via cadence config edit coverageScheme.
    SUMMARY.json gains additive, optional coverageScheme/coverageMode fields
    recording which scheme produced a settle's evidence; cadence verify coverage --explain reports per-occurrence whether a token satisfies the configured
    scheme.

  • 127a06b: BREAKING (engine floor): minimum supported Node.js raised from >=20 to
    >=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.json now 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
    engines mismatch (this repo does not set engine-strict), but CI
    pipelines or environments with engine-strict enabled will fail outright,
    and pipelines pinned to Node 20 should bump their Node version to keep
    using the cadence CLI, either host adapter, or
    @manehorizons/cadence-types.

  • 92ae02e: cadence doctor gains a ledger-remote-collision check (rec-20260726-003):
    mintId computes 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
    checkRemoteFreshness fetch plumbing), resolves git 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 (never error) on
    any overlap and naming the colliding id(s). It degrades safely to ok — 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
    --fix auto-repair exists for this finding — resolving a real collision
    needs a human to pick which side re-mints, matching worktree-phases.

  • d7d4239: SUMMARY.json gets 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, additive contentHash: { algorithm: 'sha256'; value: string } field — existing SUMMARY.json records without
      it keep parsing unchanged.
    • cadence settle run now computes a sha256 digest over a canonical
      (deep, stable-key-order) stringification of the settled summary and
      attaches it before writing SUMMARY.json/SUMMARY.md. Both cadence summary render and the settle-time SUMMARY.md sidecar display it.
    • New cadence summary verify <phase> <num> recomputes the digest and
      reports MATCH, MISMATCH (non-zero exit — the stored hash doesn't
      match the content, i.e. the file was edited after settle), or NO_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 EnterWorktree git worktree (or a fresh
    clone) carries the committed .cadence/ scaffold but never state.json
    (gitignored since phase 196), so every state-mutating command threw
    NotInitializedError saying "run cadence init" — but cadence init
    correctly refuses on an already-.cadence/-committed repo, a dead end that
    had to be worked around by hand-authoring state.json (hit live during
    phase 222). cadence onboard already bootstraps exactly this case safely
    (phase 196 fallout, #177), but nothing in the failure path pointed at it.
    SimpleStateBackend.readState()'s NotInitializedError now distinguishes
    ".cadence/ doesn't exist at all" (still names cadence init) from
    ".cadence/ exists but state.json is missing" (now names cadence onboard), and cadence init's "already initialized" refusal prints an
    additional line pointing at cadence onboard in the same missing-state.json
    case. cadence init still refuses and writes nothing either way — only the
    guidance changes.

  • 0e854cd: Extracted a shared runConvergentReview primitive (in packages/core/src/verify/converge.ts,
    alongside nextConvergence) 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's verification-readiness check 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 — doctor printed ✓ ok while that gate was guaranteed to
    silently fall back to mock at call time. cadence config explain already
    caught this via its provider-no-key warning, and its remedy line says "Run
    cadence doctor to confirm provider health" — pointing the operator at the
    command that reported the green tick.

    assessReadiness gains seamsDowngraded: the seams whose configured provider
    is real but whose credentials are missing, in VERIFIER_SEAMS order. It never
    includes a mock seam (not a downgrade — it announces itself) nor a host-cli
    seam (no required credential by design). The existing seamsReal/seamsMock
    partition, which classifies by configured provider name, is unchanged — the new
    field expresses what that partition structura...

Read more

v1.51.1

Choose a tag to compare

@github-actions github-actions released this 26 Jul 02:08
f835470

Package Changelog

Patch Changes

  • e9f6556: Closes three confirmed CLI/MCP parity gaps in the Praxis-adjacent surfaces:

    • cadence_recommendation_promote (MCP) now accepts a ref argument and
      threads it into shippedRef exactly 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
      a status=shipped promotion (which auto-archives by default) always
      returned data: null even on full success, because the lookup only
      checked the live recommendations array, not archived.
    • The "did this milestone propose run produce any newly-proposed
      milestones" predicate — previously copy-pasted as an identical literal
      expression in both cli/commands/milestone.ts and
      services/milestone-propose.ts, a duplication class that had already
      caused one whole-branch-review-caught drift bug — is now a single
      exported hasNewlyProposedMilestone() both call sites invoke.
    • next/verify coverage/verify phase/explain logic, which already had
      the right (repoRoot, args, io) => CommandResult service shape but lived
      in cli/commands/ where the MCP surface couldn't reach it, is relocated
      into services/{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.md and
      docs/reference/commands.md are 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.json was the only
    one of the five ledger files not written with { mode: 0o600 }.

    cadence intelligence audit/reconcile/stats now include milestones as a
    fifth ledger: a new orphan-milestone finding 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-flags validation is now one shared
    pipeline instead of three independently maintained copies — behavior and
    error wording are unchanged.

    cadence-types, cadence-host-claude-code, and cadence-host-codex carry
    version-alignment bumps only; none of the three changed.

  • e05922e: Fix cadence recommendation add's id-minting to cross-check evidence.json
    (phase 219, rec-20260724-013). nextRecommendationId previously derived the
    next rec-YYYYMMDD-NNN id only from recommendations.json, so a dangling
    evidence.json row left behind by a bad rebase-conflict resolution or an
    interrupted add call — a recommendationId reference with no matching
    recommendations.json entry — could silently collide with a freshly minted
    id for an unrelated recommendation. The minted id is now guaranteed strictly
    greater than both the recommendations.json max and the max
    recommendationId referenced by evidence.json for the same date prefix.

    Also adds a new orphaned-evidence cadence doctor check that surfaces any
    evidence.json row whose recommendationId has no matching
    recommendations.json entry, 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, and cadence-host-codex carry
    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 in host-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 lost cadence-dispatch's
      DISPATCH_DIALOGUE body. Host-codex's own mapEvent/extractPayload/
      routeHookEvent stay local — its apply_patch-based extraction is
      genuinely different from host-claude-code's file_path-based extraction,
      not just duplicated; only the structurally-identical RouteResult type is
      shared.
    • install.ts's managed-marker merge logic and locate-self.ts are also
      extracted into the toolkit, with one shared test suite; both adapters'
      own install.ts/locate-self.ts are now thin wrappers.
    • Core now enforces a new HostCapabilities.agentIdentification flag: a
      host that declares it cannot supply agentId/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 to cadence 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.

  • 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