Skip to content

feat(omp): add integration observability - #1

Open
panosAthDBX wants to merge 243 commits into
fix/omp-deterministic-driver-recoveryfrom
feat/omp-integration-observability
Open

feat(omp): add integration observability#1
panosAthDBX wants to merge 243 commits into
fix/omp-deterministic-driver-recoveryfrom
feat/omp-integration-observability

Conversation

@panosAthDBX

@panosAthDBX panosAthDBX commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Summary

  • add namespaced OMP progress projections, coalesced per deterministic drive and guarded against stale generations
  • fail closed on malformed or mutated Babysitter bridge task envelopes and preserve durable single-owner completion semantics
  • clear extension-owned session bindings when lifecycle context has no real session ID without deleting externally replaced values
  • expose allocator-compatible OMP ownership and checkpoint state in Observer without copying retained transcript content
  • declare generated-package zod ^4.4.3 runtime compatibility and OMP peer range >=16.5.2 <17
  • update generated OMP docs, instructions, declarations, and regression coverage

The combined upstream PR a5c-ai#1582 now contains this exact integration commit and supersedes the underlying driver PR a5c-ai#1580. Companion OMP API PR: can1357/oh-my-pi#6522.

Compatibility / risk notes:

  • Requires the additive OMP projection API proposed in feat(coding-agent): add namespaced todo projections can1357/oh-my-pi#6522; generated metadata supports OMP >=16.5.2 <17.
  • Generated packages now declare zod ^4.4.3; a packed strict nested install compiled and imported the driver without installing the optional OMP peer.
  • Two SDK resume tests retain an unrelated macOS /var versus /private/var path baseline failure; 67 focused SDK tests passed and the SDK build passed.
  • Observer's app build retains an unrelated missing @tailwindcss/oxide-darwin-arm64 optional-binding baseline failure; Observer CLI build and 70 focused tests passed.
  • Project-wide suites, formatters, and linters were intentionally not run.

Testing

  • npm test (not run; focused matrix below)
  • npm run test:ci (not run; focused matrix below)
  • Evidence:
    • (cd packages/adapters/extensions && npm exec -- vitest run src/__tests__/ompDeterministicDriver.regression.test.ts src/__tests__/e2e.test.ts) — 40 passed, 0 failed
    • (cd packages/observer-dashboard && npm exec -- vitest run src/lib/__tests__/parser.test.ts src/lib/__tests__/omp-checkpoint.test.ts src/components/details/__tests__/agent-panel.test.tsx) — 70 passed, 0 failed
    • (cd packages/babysitter-sdk && npm exec -- vitest run src/runtime/__tests__/progressTracking.test.ts src/harness/__tests__/sessionMarker.test.ts src/harness/__tests__/sessionResolutionPrecedence.test.ts src/cli/commands/session/__tests__/iterationMessage.test.ts src/cli/commands/session/__tests__/resume.test.ts src/cli/commands/session/__tests__/lifecycle.test.ts) — 67 passed; 2 unrelated canonical-path baseline failures
    • (cd packages/babysitter-sdk && npm exec -- vitest run src/cli/commands/session/__tests__/resume.test.ts --no-file-parallelism) — reproduced exactly the 2 unrelated baseline failures with 6 passed
    • npm run verify:omp-extension-types — passed against installed OMP 16.5.2
    • npm ls @oh-my-pi/pi-coding-agent --depth=0 — resolved 16.5.2
    • npm run build --workspace=@a5c-ai/extensions-adapter — passed
    • adapter and SDK package builds plus Observer CLI build — passed
    • npm ci --ignore-scripts --dry-run and npm ci --ignore-scripts --dry-run --omit=optional — passed
    • disposable clean npm ci --ignore-scripts installed 3281 packages from the lock; generated strict pack/install/compile/import regression passed
    • npm run verify:metadata — passed
    • lock audit found 689 HTTP resolved URLs, zero non-public HTTP origins, and zero proxy origins

Docs impact

  • No user-facing docs changes needed
  • Updated generated OMP README.md and AGENTS.md
  • Updated DEMO.md
  • Updated SECURITY.md
  • Updated CONTRIBUTING.md

Screenshots / GIFs (if UI changes)

No screenshot: the Observer change adds derived checkpoint/status presentation covered by parser, checkpoint, and component regressions; it does not introduce a new interaction flow.

tmuskal and others added 30 commits June 30, 2026 17:50
The per-harness atlas READMEs told users to run
`babysitter harness:install-plugin <harness>`, which installs the BABYSITTER
plugin, not atlas. Rewrote each to install the atlas plugin via the harness's
real mechanism (mirrors the claude-code fix):

- Published atlas npm packages -> npx/native installer:
  codex/genty `npx --yes @a5c-ai/atlas-<h> install`, omp `omp plugin install
  @a5c-ai/atlas-omp`, pi `pi install npm:@a5c-ai/atlas-pi`, github
  `copilot plugin marketplace add a5c-ai/atlas-github-copilot && copilot plugin install atlas`.
- Plugin-only repos (no npm publish): cursor/gemini/antigravity/opencode/openclaw
  run the repo's bundled bin installer via `npx --yes github:a5c-ai/atlas-<repo> install`.

Verified npm publish status and external repo bin/manifests for each harness.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DmHAepM1kgrjKeiph1mKAT
…json

Claude Code's marketplace schema requires a top-level `owner` object; the root
.claude-plugin/marketplace.json was missing it, so loading the `a5c.ai`
marketplace failed with "owner: Invalid input: expected object, received
undefined". Added owner {name, email} matching the other a5c marketplaces.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DmHAepM1kgrjKeiph1mKAT
Generated harness plugins (babysitter-claude et al.) write a hooks.json that
invokes the bare `adapters-hooks` binary (from @a5c-ai/hooks-adapter-cli) for
every hook event. Plugins bootstrap via `npm i -g @a5c-ai/babysitter-sdk`, but
npm only links a package's OWN bins to the global bin dir, never its
dependencies' — so nothing put `adapters-hooks` on PATH and all babysitter hooks
were dead no-ops (exit 127). @a5c-ai/hooks-adapter-cli wasn't even a dependency.

Fix: add @a5c-ai/hooks-adapter-cli as a dependency and re-export both
`adapters-hooks` and `adapters` as babysitter-sdk's own bins (thin launchers that
re-exec the dependency CLI). Now `npm i -g @a5c-ai/babysitter-sdk` puts both on
PATH. resolveDependencyBin locates each dep via node_modules + fs (bypassing the
@a5c-ai/adapters `exports` map and @a5c-ai/hooks-adapter-cli's missing `main`).

Verified: both shims re-exec the real CLIs (adapters hooks handle Stop ->
{"decision":"allow"}); 3 unit tests cover the resolver's edge cases.

NOTE: reaching published users needs an SDK version bump + republish + a plugin
versions.json bump (6.0.0 is already published, so the idempotent publisher skips
it).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DmHAepM1kgrjKeiph1mKAT
…ness build

Mirror of the main-branch fix (de2d2d0): the harness build OOM-killed on the
7GB ubuntu-latest; move the job to ubuntu-latest-l like publish.yml.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DmHAepM1kgrjKeiph1mKAT
…arness build

The real cause of the "Lint, Tests, Package" failures on every recent PR: the
"Build babysitter-harness" / genty-core steps piped to `tee artifacts/test-lo../…`
— a corrupted path (should be `artifacts/test-logs/…`). That dir doesn't exist,
so `tee` fails to open it and, under `set -o pipefail`, fails the whole step with
exit 1 and no TS error (the babysitter-sdk build echo comes from genty-core's own
build chain, which is why it looked like an SDK/OOM failure). Fixed both paths.
Kept the larger runner (matches publish.yml for this heavy build).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DmHAepM1kgrjKeiph1mKAT
…ll docs

Two issues reported for codex:

1. `codex plugin marketplace add a5c-ai/babysitter-codex` failed with
   "marketplace root does not contain a supported manifest". The per-harness repo
   ships a `.codex-plugin/plugin.json` bundle but no marketplace root — only the
   monorepo `.agents/plugins/marketplace.json` had one (needs `--sparse`). Unlike
   claude, whose external repo gets a self-contained `.claude-plugin/marketplace.json`
   via writeRepoMarketplace (a5c-ai#955), codex repos got nothing (all targets have
   marketplaces:[] and the helper only handled .claude-plugin/plugin.json).
   Fix: writeRepoMarketplace now falls back to `.codex-plugin/plugin.json` and
   writes `.claude-plugin/marketplace.json` (the legacy root codex recognizes), so
   `codex plugin marketplace add a5c-ai/babysitter-codex` resolves without --sparse,
   symmetric with claude. Takes effect on the next external-repo sync.

2. Install docs were wrong/partial: the codex per-harness README and
   03-babysitter-plugin-flows used `--ref staging`, contradicting codex.md's
   "never --ref staging" rule. Corrected to `--ref main`, clarified that the
   marketplace manifest lives in the monorepo (`a5c-ai/babysitter --sparse
   .agents/plugins`), and documented why adding `a5c-ai/babysitter-codex` failed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DmHAepM1kgrjKeiph1mKAT
…per-repo flow

Corrects the prior attempt. Per OpenAI Codex docs, `codex plugin marketplace add
owner/repo` reads `$REPO_ROOT/.agents/plugins/marketplace.json` (codex format:
`{name, version, interface.displayName, plugins:[{name, version, source:{source:
"local", path:"./"}, policy, category}]}`) — NOT a claude-format `.claude-plugin/
marketplace.json`. writeRepoMarketplace now writes the real codex manifest into
codex repos (self-sourced at ./) while keeping claude's own format, so
`codex plugin marketplace add a5c-ai/babysitter-codex` + `codex plugin add
babysitter --marketplace babysitter` works per-repo (no --sparse), symmetric with
claude. Docs (codex README, codex.md, plugin-flows) updated to the per-repo flow.

Refs OpenAI Codex plugin docs (developers.openai.com/codex/plugins/build).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DmHAepM1kgrjKeiph1mKAT
Cryptographic policy-enforcement architecture grounded in genty trust
primitives, proven, the two existing policy engines, adapters gates, and
the transport proxy attestation seam. 33 numbered acceptance criteria
mapped to milestones A-E; one new package (@a5c-ai/policy-adapter).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rsarial review

Close all 5 blocking issues from the 62/100 adversarial security review:

1. Model-decision now binds a specific tool call: extend model-decision payload
   with signed toolCalls[] (toolCallId+name+argsHash); CommandAuthorization binds
   toolCallId (AC-34/34a; updates AC-4/§4.1, AC-12/13/15/16, AC-30).
2. Trusted-store key resolution: TrustRoot carries key material; new
   verifyEnvelopeTrusted wrapper resolves keys only from the trusted store, binds
   sha256(pubkey)==fingerprint, selects by (requiredKind, allowedFingerprints),
   rejects cross-kind (AC-35; updates AC-5/6/7/26).
3. Config integrity: trust-roots + policy docs signed by an out-of-agent config
   root-of-trust, verified before honoring; bootstrap/pin story (AC-36/37/45;
   updates threat model, §1.2, AC-26/33).
4. Must-be-signed is a runtime trust-boundary assertion, not a lint (AC-2/8/10).
5. Canonicalized argv command matching + per-env opt-in default-allow (AC-38/38a/38b;
   updates §7, AC-23).

Non-blocking folds: proxy-attestation default for credential actions (AC-39),
trusted credential->scope source (AC-40), quorum distinct-holder rule (AC-41),
argsHash recomputed at GATE 3, evidence covers every step (AC-42), proven bridge
stays human (AC-43), non-blocking-GATE-2 + passthrough denial test (AC-44).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…eview attacks

Second security review (74) confirmed Draft 2 closed the 5 original blockers
but found 3 residual blocking attacks. Draft 3 closes each precisely:

- Config rollback/downgrade: single signed config manifest with monotonic
  configEpoch covering all config files together (AC-46) + off-workspace
  min-epoch floor pinned beside POLICY_CONFIG_ROOT_FP (AC-47). Every gate
  rejects below-floor/stale epochs; revocation can't be downgraded
  independently. Revises AC-26/27/36/37/45; CommandAuthorization gains
  configEpoch (AC-8/AC-10 step 10).
- Proven-bridge unsigned approved bit: bridge now asserts legacy
  signedFields superset of {breakpointId,approved,responderId} before
  deriving human evidence (AC-48), applying the AC-2 completeness rule to the
  legacy proven answer at proven/verify.ts:60. Revises AC-3/AC-43.
- GATE 3 backstop scope: GATE 1 + genty dispatcher/session declared
  load-bearing, un-bypassable for ALL covered actions with an exec-path
  enumeration test (AC-49/AC-49a); GATE 3 extended to non-env credential
  channels (docker -v, k8s secrets) with a bounded, warned non-goal for
  IMDS/pre-existing mounts (AC-50). Revises AC-23a/33/40/44.

Folded cheaply: domain-separation payloadType constant in signedFields
(AC-51); one shared canonical argv/args serializer + conformance test
(AC-52/52a); argv wrapper allowlist (AC-38c); heterogeneous quorum
composition (AC-41a); collision-resistant credential identity, deny-on-
ambiguous (AC-40a). 65 ACs, each mapped to one milestone. No prior AC
regressed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…approval

Owner approved the proof-based policy-enforcement design (score 91) at the
design-approval breakpoint with the condition that the four non-blocking
security-review notes become required acceptance criteria:
- AC-53 argsHash proxy/gate boundary conformance + mutating-hook fail-closed (Milestone C)
- AC-54 proven canonical-form hardening under the AC-48 bridge (Milestone A)
- AC-55 credential-identity alias canonicalization before deny-on-ambiguous (Milestone B)
- AC-56 exhaustive exec-seam registry so unregistered exec paths fail the build (Milestone D)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Frozen tests authored strictly from docs/design/proof-based-policy-enforcement.md
(Milestone A — unified trust core). Cover every milestone-A acceptance criterion,
each test named with its AC id, with mandatory negative/adversarial fail-closed cases.

- genty-core: SignedEnvelope canonical-form determinism/stability (AC-1, AC-2
  groundwork); new ModelDecisionPayload/SignedToolCall tool-call binding
  (AC-34/AC-34a, AC-51).
- policy-adapter (new pkg, intended module paths): trusted-store verifier wrapper
  (AC-35, AC-2, AC-5/6/7, AC-51, AC-27); CommandAuthorization shape + verification
  incl. configEpoch floor (AC-8/9/10/42, AC-46/47, AC-51); config-integrity
  manifest + anti-rollback (AC-26/36/37/46/47); proven->SignedEnvelope bridge
  legacy-completeness (AC-3/43/48); chain verification extensions (AC-35g).
- tasks-adapter: proven canonical-form hardening — no collision, dual-read (AC-54).

Tests import from not-yet-existing implementation modules and are expected to fail
to resolve until Milestone A lands; they parse and express the contract.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Implements Milestone A of proof-based policy enforcement:

- genty-core: new ModelDecisionPayload/SignedToolCall type beside
  model-signing.ts binding each tool call {toolCallId,name,argsHash}
  with a bound payloadType constant in signedFields (AC-34/AC-51).
- @a5c-ai/policy-adapter (new package, packages/adapters/policy):
  - verifyEnvelopeTrusted: trusted-store key resolution, fingerprint
    binding, (requiredKind, allowedFingerprints) selection, cross-kind
    rejection, runtime signedFields completeness + payloadType, expiry
    and revocation (AC-35/AC-2/AC-51/AC-27).
  - verifyCommandAuthorization: full CommandAuthorization gate contract
    incl. TOCTOU hash re-checks, configEpoch floor + current binding,
    per-step evidence coverage (AC-8/AC-10/AC-42/AC-46/AC-47).
  - verifyConfigManifest: single signed manifest, monotonic configEpoch,
    off-workspace epoch floor, per-file hash + unlisted-file deny-all
    (AC-36/AC-37/AC-46/AC-47).
  - verifyTrustChainTrusted: wraps genty verifyTrustChain, per-link
    trusted-store resolution + kind (AC-35g).
  - bridgeProvenAnswer: proven -> human-approval evidence with AC-48
    legacy signedFields completeness, anchored on the original human
    fingerprint (AC-3/AC-43/AC-48).
- proven hardening (AC-54): length-prefixed, type-tagged canonical
  signing form so distinct field assignments cannot collide; verify
  dual-reads hardened + legacy so existing signatures still verify.

All fail closed: any verification/parse/config error is a deny, no
fallbacks. tsconfig references + workspace glob pick up the new package
(lockfile regeneration still required, done off-Windows).

Tests: genty-core trust 46, tasks proven 98 (full suite 1076), policy
adapter 60 -- all green. build:sdk green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Milestone-A adversarial-review defect (commit 18a73697d): the
delegation-chain linkage was never verified. verifyTrustChainTrusted
built links for genty verifyTrustChain WITHOUT populating
parentSignature, and verifyOne validated each link in isolation, so
genty's parent-linkage check (chain.ts:35) was dead code. A "chain"
passed as an unordered set of individually-trusted agent envelopes with
no real A->B->C delegation relationship — reordering or splicing a
foreign-but-trusted envelope still passed.

verifyTrustChainTrusted now verifies real delegation linkage: a chain is
recognized as linked when any link (i>0) declares an in-chain
delegatorFingerprint, and every link i>0 must then bind to its immediate
predecessor (delegatorFingerprint == predecessor signer AND
delegatorSignature == predecessor envelope signature, populated as
parentSignature so genty's check re-confirms). Fails closed on
reordering, missing/forged parent, or a spliced foreign envelope. A set
of independent roots (no in-chain delegator declared) stays valid.

Also, same trust-core guarantee:
- proven verify.ts: recompute sha256(public-key DER) and bind it to the
  claimed publicKeyFingerprint before trusting the resolved key (the
  check verify-envelope-trusted enforces but proven omitted). This is the
  signature check behind bridgeProvenAnswer's human guarantee; deny on
  mismatch.
- proven-bridge.ts: enforce the human trust root is valid at answeredAt
  (mirrors keyValidAt), so an expired human root can no longer launder
  proven answers into human evidence.

Adds adversarial coverage (no frozen test changed): reordered links,
spliced foreign envelope, forged/missing parent, valid A->B->C for the
linkage fix; fingerprint-binding and expired-human-root for the proven
and bridge suites.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gn spec

Frozen tests for Milestone B of proof-based policy enforcement, authored
strictly from docs/design/proof-based-policy-enforcement.md (§5/§7/§9/§12/§14).
Import intended @a5c-ai/policy-adapter module paths the implementation WILL
provide (resolution fails now, by design — no syntax errors).

Covers every Milestone-B AC:
- AC-52/AC-52a shared canonicalizeArgs/canonicalizeArgv (total, loss-preserving,
  byte-identical across proxy + gate; conformance corpus, no-collision, AC-53 boundary)
- AC-38/38a/38b/38c canonicalized argv matcher: sh -c recursion, abs-path/symlink
  basename, per-scope wrapper allowlist (not denylist), commandDefaultAllow opt-in;
  adversarial alias-evasion (npx/env-indirection/$()/backticks/eval/busybox/
  interpreter-indirection/unlisted wrappers) all deny, never default-allow
- AC-19/19a/38b/23c policy schema: >=2 alt chains from one doc, quorum + heterogeneous
  composition parseable; commandDefaultAllow default false; duplicate-fingerprint
  store rejection (carry-forward)
- AC-9/20/41/41a/42 evaluator: aws human+opus AND 2-human quorum both evaluate;
  wrong-model/expired/revoked/unknown-fp/scope-miss/wrong-payloadType deny; quorum
  distinct-holder (one human's two keys denied); no double-use; deny>grant precedence
- AC-9/42 issuer: configEpoch-bound short-lived CA, issue->gate re-verify loop;
  explicit requiredStepCount carry-forward (absent => fail closed); below-floor deny;
  delegation carry-forward (empty/single-link rejected, terminal delegatee confirmed)
- AC-55/40a credential-identity alias canonicalization: two-alias-one-credential to
  one scope; deny-on-ambiguous/absent/agent-supplied-alias

Milestone A frozen tests unchanged (67/67 pass).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…st-chain evaluator + authorization issuance)

Adds the @a5c-ai/policy-adapter configurable policy component on top of the
Milestone-A trust core:

- canonicalize-args.ts: ONE shared, total, loss-preserving argv/args serializer
  (AC-52/AC-52a/AC-53) — deep-sorted object keys, preserved array order/types/bytes,
  explicit deny-path (throw) for non-finite numbers.
- argv-matcher.ts: canonicalized argv matcher (AC-38/38a/38b/38c) — tokenize,
  recurse into sh/bash/zsh -c, resolve argv[0] basename, per-scope wrapper ALLOWLIST,
  commandDefaultAllow opt-in; all alias forms ($()/backticks/$VAR/eval/npx/busybox/
  interpreter-indirection/unlisted-wrapper) fail closed instead of evading coverage.
- policy-schema.ts: policy document parser/validator (AC-19/19a/38b/41/41a/23c) —
  requirements[] with typed steps + distinct-holder quorum, legacy steps[]/quorum:
  sugar normalized; plus loadTrustStore duplicate-fingerprint rejection.
- policy-evaluator.ts: trust-chain evaluator (AC-9/20/22/41/41a/42) — verifies every
  envelope via verifyEnvelopeTrusted/verifyTrustChainTrusted, condition sugar compiled
  to base operators, deny>grant precedence, no-double-use, delegation carry-forward
  hardening (reject single-link non-delegation, confirm terminal delegatee), fail closed.
- authorization-issuer.ts: short-lived configEpoch-bound CommandAuthorization issuance
  (AC-9/42/47) — explicit requiredStepCount required, fail closed on unverified evidence
  / below-floor epoch / missing step coverage.
- credential-identity.ts: alias canonicalization + deny-on-ambiguous (AC-55/40a).

Reuses the two existing engines' condition operators + precedence (AC-22); no third
engine. All 146 policy-adapter tests pass (67 frozen Milestone-A + 79 Milestone-B).

Adds `yaml` dependency (already at repo root) — lockfile regeneration needed on CI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ld-ins

Adversarial review (score 46) found the Milestone-B policy engine passed only
happy-path (theatrical) tests. Fix at root cause and add the missing adversarial
assertions:

1. AC-34a/AC-30 model-decision tool-call binding: evidenceSatisfiesStep now
   requires the verified attestation's signed toolCalls[] to contain an entry
   whose toolCallId===context.toolCallId AND argsHash===context.argsHash (shared
   canonicalize-args bytes); mismatched id/argsHash or empty toolCalls => deny.
2. AC-38/38a/38c argv anti-evasion: the evaluator now routes action matching
   through the canonicalized matchArgv (shell -c recursion, per-scope wrapper
   allowlist, deny-on-unresolvable) instead of naive basename matching. Disguised
   covered commands (sh -c, nested sh, npx, A=aws;$A, $(...), backticks, eval,
   busybox, python/node -c) resolve to the covered program and DENY.
3. AC-41 quorum distinctness: humanIdentity resolves the RESOLVED trusted-store
   identity (TrustRoot identityId/label) instead of the attacker-signed payload
   approvedBy; two keys owned by one trusted identity count as ONE.
4. Anchor unanchored regexes (modelIdMatches, subcommandMatches x2) as ^(?:x)$.

Folded-in security fixes:
5. AC-17/39 requireProxyAttestation enforced: defaults to true for any
   credentialScope-touching action; an in-process (agent-held) attestation is
   rejected unless the policy explicitly opts out (producer:'proxy' marker).
6. Issuer grant gate: new issueFromDecision consumes the evaluator's
   PolicyDecision (granted===true) and binds the EXACT granted action
   (toolName/commandHash/argsHash/credentialScope/toolCallId/configEpoch).
   Also add the empty-requirements/requiredStepCount===0 => unsatisfied guard.

Fixtures corrected (not weakened): proxy engine roots marked producer:'proxy'
so the AC-39 credential-scope default is satisfied for a valid fixture.

170 policy tests pass (was 146; +24 adversarial). 67 frozen Milestone-A tests
unchanged and green. build:sdk green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tmuskal and others added 13 commits July 23, 2026 13:23
…rt, incident-management, contract-lifecycle, full-cycle-hiring

Owner-steered enrichment run 01KY6X5FN64XTQT6V21B84WG1N: four full end-to-end work
workflows, all passed adversarial executed-evidence gates on attempt 1.
- customer-support/ (NEW specialization): ticket-lifecycle.js — triage, parallel
  investigation, adversarial resolution gate, policy-gated reply/refund/KB-publish.
- incident-management/ (NEW specialization): incident-lifecycle.js — consolidates
  devops-sre incident-response, itil-incident-management, observability lifecycle;
  severity-routed policy gates, postmortem completeness gate.
- legal/contract-lifecycle-workflow.js: supersedes contract-lifecycle-management.js
  (deprecated in place); redline gate with executed coverage check, per-round
  negotiation approvals, gated send/accept/sign.
- human-resources/full-cycle-hiring-workflow.js: supersedes full-cycle-recruiting.js;
  JD + panel-calibration bias gates, comp approval hard pre-gate of offers.
All declare policyGatedActions (breakpointId=actionId, adapters/policy-ready evidence),
reuse routed-gate-combinators, and kip recall/assert per domain. Plan updated with
owner throughput decision (auto-slates, two ~12-item batches next).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…partially closes D-61)

A learned graph retained a superseded design-choice edge as status:"current", so
kip ask presented a superseded choice as present-tense. Fix (owner-chosen retrieval
locus; proj UNTOUCHED, getNode unchanged): a supersedes edge convention
(edgeKind:"supersedes", from=new, to=old — an ordinary signed fact) surfaced in
graph-QA. A node reached as the LIVE (D-68 edgeExistenceFactId) to of a supersedes
edge is historical: its status:"current" is OVERRIDDEN to "superseded" (not just
flagged — the D-60 lesson) on the node and its outgoing claim edges, plus
superseded/supersededBy markers and the citable supersedes edge. A retracted
supersedes reverts to current.

Adversarial round (critic 72 -> fixed): the first cut leaked — supersession was keyed
by literal eid and NOT expanded across the same_as class, so a superseded decision
described across two same_as-merged documents leaked status:"current" under the alias
eid (getNode redirects to canonical; §3a reads alias cells) in BOTH directions — the
same D-60-class masking. Corrected by expanding supersession across repo.sameAsClass
(every member mapped to the min live supersedes factId). Independently re-verified:
zero "current" leaks for any class member, both directions. The D-60 composition
(conflicted AND superseded) applies the same override; overclaim removed.

Honest scope (PARTIALLY ADDRESSED): deterministic retrieval surfacing shipped; model
extraction of supersession is KIP_LEARN_LIVE-gated + nondeterministic; getNode-direct
projection and true bitemporal validTo (learn validFrom is 0) are documented follow-ons.

proj UNTOUCHED, deterministic, INV-A1/read-only, N5, zero deps. ADR-B16.
Suite 974 passed | 8 skipped (+8, incl. both same_as directions).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…herent, no clean fix ships

Investigated D-58's three suggested levers and found none applies, so recording the
grounded finding rather than shipping cosmetic code that would overclaim a determinism
the model path cannot provide:
- Pin temperature/seed: NOT AVAILABLE — claude CLI v2.1.195 exposes no
  --temperature/--seed/--top-p/sampling flag (verified via --help); no seam to pin.
- Canonical AssertInput ordering: MOOT — proj projection is set-pure/order-independent,
  so ordering the compiled array does not change the resulting graph (cosmetic).
- Deterministic slug re-derivation: REJECTED — folds genuinely-distinct entities that
  normalize to one slug (cross-entity collision), needs model-coupled identity
  detection, churns frozen eids.
The core node/edge DECOMPOSITION variance is intrinsic to the accelerator-class model
encode. The cross-run eid-instability CONSEQUENCE is mitigable downstream via the
entity resolver's same_as linking (ADR-B11/B12; read-reversible since D-68). Status:
Open/INHERENT, honestly documented as accelerator-class, not a determinism guarantee.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…s 12 domains

Auto-slate enrichment run 01KY78D4SQ0WX1C73HHEWKXJ8W (owner throughput authorization):
all 12 passed adversarial executed-evidence gates on attempt 1.
NEW specializations: release-engineering (release-lifecycle.js), data-privacy-compliance
(dsar-lifecycle.js, statutory-clock deadline routing), procurement (procurement-lifecycle.js,
spend-threshold routing). New flagships in existing domains: research-publication,
marketing-campaign, sales-deal (supersedes pipeline-review-forecast), finance-month-end-close
(supersedes financial-statement-preparation), product-lifecycle-e2e,
multi-audience-announcement (+ communication README). First 3 implemented methodology
compositions: legacy-modernization, regulated-greenfield, startup-mvp.
All declare policyGatedActions (adapters/policy-ready routed breakpoints, fail-closed
executors), reuse routed-gate-combinators, kip recall/assert per domain kind.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rl) — closes D-67 remote half via safe design

kip ingest-rdf --url <https-url> fetches N-Triples from an explicit host allowlist
and feeds the bytes VERBATIM to the existing rdfToAcquisition -> runAcquisition path,
so the D-67 untrusted-data guards (reserved-channel forge refusal, malformed
strict-fail, INV-A1) already apply to fetched content. The fetch layer only ACQUIRES
bytes; it never parses or authors.

Safe by design: opt-in gate KIP_RDF_FETCH (comma-separated host allowlist; unset =>
DISABLED, the default — no network call in the CLI or the whole suite; gate-off /
non-allowlisted host => exit 7 before any network call); EXACT case-insensitive
hostname match (no suffix/subdomain — evil-dbpedia.org != dbpedia.org, fails closed
on trailing-dot/IDN-homograph); HTTPS-only; embedded credentials refused; GET-only,
no cookies/auth/added-query, fixed Accept; redirects refused outright
(redirect:manual); hard caps (5 MiB STREAMED byte count — Content-Length not trusted
— + AbortController timeout); injectable fetchImpl so the suite hits NO real network.
Zero new deps (Node global fetch).

Security review (score 85 -> fixed): every bypass fails closed (userinfo-SSRF caught
by the credentials check first; redirect refusal covers 3xx + undici opaqueredirect
before the body read; streamed cap with reader cancel). The one finding was an
HONESTY gap — the private-IP/metadata SSRF residual was real but undisclosed. Fixed
two ways: (1) DEFENSE-IN-DEPTH — loopback/link-local/metadata IP LITERALS (127/8,
169.254/16 incl. 169.254.169.254, 0/8, IPv6 ::1, fe80::/10) refused BEFORE the
allowlist, even when allowlisted (verified: metadata/loopback/[::1]/[fe80::1] all
refused, no network hit; public 8.8.8.8 still fetches); (2) DISCLOSURE — ADR-B14 +
DEBTS now state the residual: an allowlisted HOSTNAME resolving to an internal IP IS
fetched (only IP-literals are blocked); bounded (no rebinding TOCTOU; body parsed
locally, never returned — internal-probe/data-poison, not exfiltration); per-host
opt-in + https + no-redirect. A private-range/DNS SSRF block is deferred.

Still deferred: open/arbitrary-URL fetch, SPARQL, Turtle/JSON-LD, auth'd endpoints.
ADR-B14 addendum. Suite 1010 passed | 8 skipped (+36 fetch tests, all injected).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…query, dep-free fuzzy default + real-embedder seam (D-57 semantic half)

Owner-approved N2/N5 stance lift: kip now embeds the query itself and drives the
existing vector half of recall (the matching machinery + corpus-embedding seam
already existed; the stance was the only blocker).

- defaultEmbed (src/embed/default-embedder.ts): dep-free 1024-dim L2-normalized
  signed-feature-hashed vector over stemmed tokens + char-3-grams. FUZZY character/
  token OVERLAP, explicitly NOT learned semantics (header: 'Do NOT call this
  semantic'). Boundary pinned: revenue-recognition vs booking-settlement cos=0.0000.
- computeRecall embeds q.text when q.semantic===true and no q.embedding — via the
  INJECTED embedding microagent if wired, ELSE defaultEmbed (branched on
  hasInjectedDispatch AVAILABILITY, NOT a try/catch — a failed injected embedder
  throws loud, N5; 'fallbacks are evil'). Query + corpus embedded SYMMETRICALLY by
  the same embedder, never mixed.
- Opt-in via RecallQuery.semantic (kip ask/recall --semantic, KIP_ASK_EMBED),
  resolved outside computeRecall (stays pure). Default recall BYTE-IDENTICAL — the
  m4 'kip NEVER embeds the query text' test stays green, now guarding the off path.

HONEST (no overclaim): the dep-free default is fuzzy overlap, NOT synonymy — the
canonical revenue-recognition==booking-settlement case is still not matched. TRUE
synonymy needs an INJECTED real embedding model via the §5.3 seam (proven by a
scripted synonym-aware dispatch test); kip stays zero-dep (claude CLI has no
embeddings API). §5.3 boundary intact (embeddings outside proj; INV-A1), N5/§6.1b
anchoring preserved (subject-absent node still abstains), deterministic.

Adversarial critic 93/100. Two disclosed nits: --semantic mode-gate name; sim>0
fuzzy noise floor (follow-on). ADR-B17. Suite 1021 passed | 8 skipped (+11).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…c CLI surface was unreachable)

An end-to-end live scenario caught that 'kip ask --semantic' and 'kip recall
--semantic' both exit 2 'unknown option --semantic': --semantic was never added to
BOOLEAN_FLAGS in cli/args.ts, even though cmdAsk/cmdRecall read flagBool(flags,
'semantic'). So the entire D-57 semantic CLI surface was unreachable, while the SDK
recall({semantic:true}) path worked — which is exactly why the mock/SDK-level tests
missed it (same class as the D-69 --force gap). Fix: register 'semantic' in
BOOLEAN_FLAGS. Add CLI-parser tests asserting kip recall/ask --semantic parses to
flags.semantic===true (boolean, positional not swallowed) so the registration can't
silently regress again.

Suite 1023 passed | 8 skipped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ith getNode/edgeEids (E2E-caught)

The end-to-end scenario surfaced that edge valid-time was read inconsistently:
- plain getEdge did NOT gate on the edge's OWN validity, while getNode DID
  (nodeLiveVisibleAt) and edgeEids DID (edgeExistenceFactId(_, null)) — so a
  finite-validTo edge read 'present' from getEdge but was dropped by edgeEids (two
  reads disagreeing at the same instant; asymmetric with the node side);
- asOf({validTime}).getEdge applied only the prop-segment lens and never gated edge
  existence, so it returned an edge OUTSIDE its own [validFrom, validTo) interval
  (a validFrom:2024 edge read live at validTime:2023, an expired edge read live 'now').

Fix: both getEdge paths now gate on the edge's OWN validity via edgeValidAt(eid,
instant) — the exact analogue of getNode's nodeLiveVisibleAt gate — while STILL not
gating on endpoint-node existence (an edge is its own entity). Reuses the same
edgeValidAt authority the D-68 fold uses; the proj-INTERNAL getEdge that fold calls
is a different function and is unaffected (it already gates on edgeValidAt first).

Verified: getEdge/edgeEids now AGREE on a finite-validTo edge (both absent) and
match the node side; asOf({validTime}).getEdge reads a bounded edge present ONLY
inside its interval (null before validFrom, null after validTo). Zero regression —
full suite 1023->1029 passed | 8 skipped (all D-68/D-66/traverse/bitemporal tests
still green). Localized to the two KipRepo.getEdge read wrappers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… facts + validate in proj as a quarantine (opt-in), never a write gate (ADR-B18)

Closes the DECLARATION + current-version validation half of the docs/21 §3 ontology
gap (previously designed-not-built). Architecturally correct per the spec: a
signature is the SOLE write gate, so a schema violation is NEVER a write-time reject
(that would break set-union CRDT convergence) — it is a proj-time QUARANTINE.

- registerSchema(def: NodeKindDef) authors ONE signed { kind:'schema',
  ontologyRef:'kip:node-kind/<kind>' } fact (orchestrator-signed channel, INV-A1);
  validFrom from the repo clock so it is bitemporal. getSchema(kind, asOf?) reads the
  orderKey-winner back, as-of-queryable. NodeKindDef/EdgeKindDef/PropSchema ported to
  types.ts; NodeView.schemaViolations?: string[] added.
- proj folds the declared ontology once (collectDeclaredNodeKinds, pure over facts)
  and validates each node of a declared kind (validateNodeAgainstSchema): a missing
  required prop or a wrong-typeof prop surfaces kip:schema-violation. Node/props never
  dropped, value never invented (N5). Kind preserved (not overwritten).
- OPT-IN / non-breaking: an undeclared kind is validated against nothing → projected
  exactly as before. Grow-only: a schema declared later re-projects existing nodes.
  Deterministic: pure fold, orderKey-winner selection, sorted messages.

Convergence critic 92/100. Fixes applied: (a) determinism guard — a schema fact is
applied only when its ontologyRef matches its own payload kind, so a ref/payload
mismatch can't make winner-selection Map-ingest-order-dependent (proj determinism no
longer relies on writer discipline); (b) a disputed kip:conflict node drops
schemaViolations (uniform with the tie path); (c) +3 hardening tests (retracted
required prop → 'missing' no-phantom; same_as alias validates against the canonical
kind; re-declared stricter schema's orderKey-winner supersedes). Known Slice-1 limit
(blob-backed prop typed 'object') documented.

DEFERRED as follow-on slices (no overclaim): per-fact-version upcasters / migration /
rename / deprecate; EdgeKindDef depth; cardinality / inverse; per-kind cellReducer +
identity; and the reusable importable schema LIBRARY.

proj UNTOUCHED for write-gating; NUL count preserved (7); LF; zero new deps; lockfile
untouched. Suite 1045 passed | 8 skipped. ADR-B18.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…(registerSchemaLibrary/get/list), manifest as versioned fact, orderKey-convergent (ADR-B19)

Packages Slice-1 node-kind defs into a named, versioned SchemaLibrary manifest
that imports as facts and re-declares its member kinds (proj re-validates nodes
against the new winning def, grow-only). Selection is maxByOrderKey(...).winner
so a colliding-declared-id manifest tie resolves by the same content tiebreak as
getSchema — convergent across replicas, never a write-time gate.

Honest limits documented (ADR-B19 + types): version is last-write-wins by orderKey
(descriptive, not a monotonicity guard — a lower version registered later still
supersedes); member kinds share the global kip:node-kind/<kind> namespace (two libs
declaring the same kind resolve to one shared winning def); list echoes the declared
manifest kinds while get hydrates the currently-resolvable subset; retracting a member
kind does not un-declare it (Slice-3 evolution work).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…neage + deprecation advisory), applied at proj-time as a read-time view (ADR-B20)

NodeKindDef gains `renames` (a prop-rename lineage: old and new name are the
SAME slot, so old-named data satisfies a new-named requirement, resolved
transitively + cycle-safe, type-checked against the current type) and
`deprecated` (a node still carrying a deprecated prop surfaces a
`kip:schema-deprecated` advisory on the new SEPARATE NodeView.schemaDeprecations
field — never a schemaViolations entry, never a drop). Both serialize through the
same registerSchema channel (getSchema + library re-hydration round-trip them),
parse all-or-nothing (present-but-malformed => def declares nothing), and are
rejected up front by the Slice-2 strict library validator.

Pure, convergent, no write gate: everything is a read-time VIEW over unchanged
facts, a deterministic function of the single winning schema fact. A renames-free
def validates byte-identically to Slice 1. Arbitrary per-fact-version CODE
upcasters are documented as architecturally impossible in a convergent fold
(retired, not deferred); schema retraction + required-with-default stay named
follow-ons.

Adversarial convergence/determinism critic found NO MAJOR issues; its minors
applied: reserved kip:conflict kind is never validated, the dead `?? [spec.name]`
fallback removed (repo no-fallback rule), duplicate deprecated names deduped, and
two critic-requested tests added (disputed node drops schemaDeprecations;
multi-alias wrong-typed message is stable across authoring orders).

Full kip suite green: 1084 passed | 8 skipped. proj.ts NUL sentinel count intact.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-snapshot, idempotent, parent-chained) sharing txn()'s exact tree recipe (ADR-B21)

commit(message?) was a throwing stub. It now flushes the repo's auto-batched,
already-durably-ingested content facts (assert/retract/supersede/re-attest — so
schema facts and retracts publish too) as a new parent-chained git commit and
advances the CommitTipStore tip, returning the commit CID.

Recipe parity, no drift: the combined writeFactsTreeAndCommit was split into
writeFactsTree + writeCommitForTree (a mechanical, byte-identical extraction, so
txn() is unchanged), and commit() reuses writeFactsTree with the SAME
orderKey->compareByContent sort txn uses. A txn() commit followed by commit() over
the identical fact set is a no-op returning the txn's own oid — proving both build
the same tree.

Idempotent no-op (tree unchanged => return the existing tip, never an empty-delta
chain; always correct since currentFacts() is append-only). Loud on empty
(ERR_MALFORMED_INPUT, N5 — no honest CID for an empty publish). Advances only the
COMMIT tip; seq/hlc were already persisted per-fact by the ordinary ingest path.

Adversarial critic found one MAJOR (M1): commit() bypassed the txn single-flight
guard — a mid-txn commit() would publish a stale snapshot and clobber the tip.
Fixed: commit() now rejects ERR_TXN_ALREADY_ACTIVE while a txn() is in flight.
Its other axes (txn byte-identity, recipe parity, idempotency, N5, durability)
came back clean; its test-gap asks (G1 multi-fact parity, G4 no-op-after-reopen)
are added.

Full kip suite green: 1094 passed | 8 skipped. proj.ts untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
tmuskal and others added 14 commits July 25, 2026 16:13
…ions now implemented

Final auto-slate enrichment run 01KY7W26BV6M3BVHNGCQJF4FJ9: 12 authored, all passed
adversarial executed-evidence gates (9 attempt-1, 3 after one scoped fix round each).
- New/built-out specializations: observability (slo-lifecycle.js + incident-lifecycle
  deprecation pointer), accessibility (supersedes web-development seed), internationalization,
  mlops, developer-relations.
- New flagships: customer-onboarding-e2e (customer-support), supply-chain-fulfillment-e2e.
- business/sourcing vestigial dirs folded with deprecation pointers.
- Composition methodology Examples 1/5/6/7 implemented — all 7 now done.
Gates caught 3 real defects (JSDoc gap, ingredient-shape bug, siloed kip kind), fixed+re-verified.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ce at the channel ref

The documented_install codex lane was red on staging: it ran the monorepo
sparse form (`codex plugin marketplace add a5c-ai/babysitter --ref staging
--sparse .agents/plugins`), which reads the committed
`.agents/plugins/marketplace.json`. That manifest pins `source.ref: main` /
`6.0.2` (set for the 6.0.2 main release), so codex resolved babysitter-codex@main
= 6.0.2 while the staging channel publishes 6.0.3-staging.bf012dbb7bff — a
STALE-plugin assertion failure.

The docs already disavow that exact command ("never `--ref staging`" for the
monorepo form) and document the per-repo marketplace as the primary path.
babysitter-codex is synced per branch and its root
`.agents/plugins/marketplace.json` is channel-correct, so switch the lane to
`codex plugin marketplace add a5c-ai/babysitter-codex --ref <channel>`,
mirroring what the claude-code lane already does with `@<channel>`.

Adds a guard test that the codex commands never regress to the sparse form,
and documents the prerelease `--ref <channel>` form in the codex harness guide.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@
…mains and the classic-methodology bar retrofit

Fifth batch of the process-library enrichment epic, run through
meta/library-enrichment. All 12 items cleared adversarial executed-evidence
gates (5 on attempt 1; 7 after one scoped fix round, each a real defect).

Flagship workflows (each declares policyGatedActions on routed breakpoints,
composes point processes BY NAME, and carries kip recall/assert):
- domains/science/biomedical-engineering: medical-device-tplc
- domains/science/civil-engineering: design-to-construction
- domains/social-sciences-humanities/social-sciences: empirical-study-lifecycle
  (first flagship in that tier)
- domains/social-sciences-humanities/healthcare: clinical-safety-quality
- domains/business/knowledge-management: knowledge-lifecycle
- domains/business/project-management: program-delivery
- domains/business/venture-capital: investment-lifecycle
- security-compliance: security-attestation
- data-engineering-analytics: data-product-lifecycle
- qa-testing-automation: release-quality-assurance

Classic-methodology bar retrofit: scrum, kanban, xp-process, waterfall,
v-model, shape-up, domain-driven-design and atdd-tdd gain routed breakpoints,
adversarial gates and kip touchpoints without homogenizing their domain
semantics (9 distinct gateIds, 18 distinct critics, zero shared ironLaw
sentences); adds methodologies/production-contract.

Structural hygiene: READMEs for authoring/, collaboration/, media/; two
SKILL.md; batch-4's half-applied fold repaired — sourcing/ and business/ now
hold header-only @deprecated aliases and the canonical files are tracked.

release-quality-assurance namespaces defineTask ids across 13 sibling
qa-testing-automation files: defineTask registers into a globalThis-pinned
singleton, so co-importing the point processes threw DuplicateTaskIdError at
module 4 of 19. Id-strings only; no exported binding, task body or schema
changed, and the ids had no external referents.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… installs

All three vanilla lanes of live-stack-published have failed since 2026-07-03 at
the very first install command:

  npm error 404 '@a5c-ai/policy-adapter@6.0.3-staging.bf012dbb7bff' is not in
  this registry.

packages/adapters/policy was `private: true`, but the policy Milestone C/D work
(15f6e38, 5ed5f6a) made it a runtime dependency of three published packages
— comm-adapter, tools-adapter and transport-adapter. @a5c-ai/adapters pulls in
transport-adapter, so `npm install -g @a5c-ai/adapters` 404s for every user, not
just CI. @a5c-ai/trust-core is private for the same reason and sits one layer
below policy-adapter, so both have to ship.

Drops `private: true` from both, adds publishConfig.access, registers them as
public surfaces in the docs-coverage manifest (with the README that
check-package-metadata requires), and wires build+publish steps into both publish
workflows — trust-core in the foundation group, policy-adapter in its own
sequential step between the foundation and its consumers.

Verified: verify:metadata passes, guard-package-integrity passes, npm pack
produces both tarballs, trust-core 46 tests and policy-adapter 230 tests green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…lished install

With the policy-adapter E404 fixed, the vanilla published lanes got one command
further and hit the next break:

  npm error code EEXIST
  npm error File exists: /opt/hostedtoolcache/node/22.23.1/x64/bin/adapters

@a5c-ai/babysitter-sdk re-exports `adapters` and `adapters-hooks` as its own bins
(bd11c5b, 2026-07-01) so a standalone SDK install still puts them on PATH.
@a5c-ai/adapters and @a5c-ai/hooks-adapter-cli own those names, so installing both
globally is impossible in either order — npm refuses to overwrite an existing bin.
The E404 masked this since it landed.

Installs the SDK first, then lets the canonical owners reclaim their bins with
--force. Order matters: the SDK's dependency range is ^6.0.0, which does not match
a 6.0.x-<channel>.* prerelease under semver, so leaving the shim in place would
silently exercise the last RELEASED adapters instead of the channel build.

The edit is inside the &published_steps anchor, so all four published lanes get it.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants