Repository navigation
feat(spec): Capability Kit manifest identity, OperatorBindingDTO and OpportunityDTO v0 contracts (interface-only; not before wave D) - #397
Merged
Conversation
…OpportunityDTO contracts These are interface-only contracts for the kits lane (ledger R5/R6/R7/R8/R41/ R45, PX-13). They add no routes and no storage. adk (R4), readmodels (PX-7), operator-ux (PX-11) and refvertical (R46) build against them. - capability-kit.ts: CapabilityKitManifestV1 (strict zod). The kit references existing artifacts by digest: a CSD pinned by its capabilityContractDigest; adapter, method, tests, install and provenance recipes; machine-native labware, PLR and CAD files; and economics-lane terms hashes. computeKitDigest = sha256(canonicalize(normalized)), the same construction as capabilityContractDigest; list order never changes the digest. parentKitDigest records fork and revision lineage. validateKitCompleteness separates a reusable kit from a one-off listing (implementation, tests, install recipe, provenance recipe, license). - operator-binding.ts: OperatorBindingDTO v0, the shape agreed with operator-ux (#2896/#2944). moneyAuthority is the literal "none"; claim rights must come from bindings; payee destinations are masked (maskPayoutDestination) and a schema refuses an unmasked address. - opportunity.ts: OpportunityDTO v0. There are three kinds: funded_offer, kit_build_request and demand_aggregate. "funded" requires an authoritative, server-verified source. Aggregates are banded signals with no reward. Amounts are base-unit strings, titles are single-line and server-templated, and there are no requester fields. Tests: kits-contracts.test.ts (18) covers digest determinism across key and list order; every content change moves the digest; invalid manifests get no identity; fork lineage; completeness; money-authority and masking invariants; and funding and aggregate invariants. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FT8WYWkfig4KNcxtMqvMuj
…s (#3058) - All three contracts are marked "v0, frozen for consumers": adk, readmodels, operator-ux and refvertical ack any change on the bus first. - computeKitDigest documents that it uses @pcc/spec's single canonicalizer and pins two golden vectors (a minimal kit and the full lab/workcell kit). The minimal vector was re-derived independently in Python, and both are re-run when the canonicalizer changes (N15 / PR #359). - OperatorBindingDTO states the payout boundary: the payee is a masked read of the server-resolved destination (N21), and a binding sets, changes and authorizes no payout and grants no spend authority (R41). - A demand_aggregate OpportunityDTO carries only painpoints' public projection fields; location, evidence and deadline are refused. Tests: kits-contracts 21/21 (3 new); spec 818/818; tsc clean. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FT8WYWkfig4KNcxtMqvMuj
The consumers acked this on the bus: readmodels (#3623), adk (#3785) and refvertical (#3571, #3792). - A2: OpportunityDTO.capabilityContractDigest pins the exact CSD revision. It is REQUIRED on a funded funded_offer, because the accepted plan pins it; optional on kit_build_request; forbidden on demand_aggregate. - A3: evidence.requiredEventClasses: string[] becomes evidence.requiredPrimitives: CsdEvidencePrimitiveRef[], the same grammar as a CSD's evidence refs and setup's EmitterDecl emits[]. Each id must be active in EVIDENCE_PRIMITIVES, so the ADK's provenance planner compares supply against demand with no mapping table. - A4: the manifest header states two conventions. The provenance-recipe mediaType is application/vnd.pcc.provenance-recipe+json;v=1, and compatibility.interfaces uses the kernel's AdapterType names, never "mock". There is no shape change. - A5: a demand_aggregate carries releasePeriod (YYYY-MM), required there and forbidden elsewhere. asOf stays the READ time for every kind (readmodels' counter), so it never says when an intent happened (#365 F4). - A6: artifact names must be safe relative POSIX paths. Before, the schema accepted '../../etc/passwd', a path traversal for any installer that writes artifacts by name. Refvertical's real R46 kit already complies, so its kitDigest is unchanged. - One CSD_CAPABILITY_URL_PATTERN is now shared by the kit manifest and OpportunityDTO. Golden kit digests are unchanged (A6 only validates). kits-contracts passes 26/26 (5 new). With the source changes reverted, 8 fail. The full spec suite passes 823/823 and tsc is clean. A1, the OperatorBindingDTO part, follows separately: operator-ux, its last acker, is paused (steward #4029). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FT8WYWkfig4KNcxtMqvMuj
OperatorBindingDTO capability types become CSD urls (adk's ask (a) in
#3152, with A1b acked in #3785).
- bindings[].capabilityType and executionAuthority.canClaimCapabilityTypes
must match CSD_CAPABILITY_URL_PATTERN, the same pattern as OpportunityDTO
and the kit manifest. A Work Inbox or the ADK's match compares them
directly, so a legacy '3d-printing' can no longer silently match nothing.
- NEW unmappedCapacity: {kind, id, legacyType}[] (required, may be empty)
lists capacity whose legacy type resolves to no CSD. It is never
claimable, and it shows the operator why that capacity matches nothing.
operator-ux acked A1 (#3997) and asked that claim rights stay derived only
from mapped bindings. The superRefine already does that, and the test
"unmapped capacity can never become claimable" pins it. Steward #4111:
land it normally with A2-A6.
Tests: kits-contracts passes 30/30 (4 new). Against the old
operator-binding.ts, 2 of the 4 fail (the CSD-url binding and the required
unmappedCapacity). The other two are defense in depth: the old schema
already refused them, by claim binding and by strictness. The spec suite
passes 827/827 and tsc is clean.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FT8WYWkfig4KNcxtMqvMuj
…fact roles) KIT_ARTIFACT_ROLES gains "intake-schema" (the filled human-intake record schema, ADK-track item 6) and "safety-envelope" (sensors' R8 operational envelope). A device kit can then ship the onboarding artifacts the ADK produces. The change is additive: every existing manifest and golden digest is unchanged, and an unknown role is still refused. adk acked as a consumer (#4099). refvertical, the other manifest producer, is asked on the bus before this is pushed. Tests: kits-contracts passes 32/32 (2 new), the spec suite 829/829, and tsc is clean. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FT8WYWkfig4KNcxtMqvMuj
Each finding was reproduced on b9f3491 before it was fixed. - CRITICAL 1: OpportunityDTO is a strict discriminated union. A demand_aggregate carries no free text: its id and title are derived (demandAggregateId / demandAggregateTitle), its capability slug must be publishable (isPublicCapabilityUrl), and kitRef, location, evidence, deadline, reward and digest are refused. - HIGH 2: validateKitCompleteness is documented as STRUCTURAL only. It counts only a valid SPDX expression (isSpdxLicenseExpression) or a rights-terms hash as a license, and refuses one artifact standing in for several required roles. - HIGH 3: a funded opportunity names its authoritative funding record (fundingRef); a funded kit_build_request needs authority and the record. - HIGH 4: evidence requirements carry executable, true exactly when every primitive has a live verifier; funded work must be executable; params are validated against each primitive's paramsSchema. - MEDIUM 5: payee masks match exactly the two shapes maskPayoutDestination produces; availability is a closed typed summary. - MEDIUM 6: duplicate set entries and non-NFC text are refused; lists sort by Unicode code point. - MEDIUM 7: asOf, deadline and binding timestamps are ISO timestamps; a release period must have closed before asOf. - MEDIUM 8: every shape or enum change bumps the schema literal, pinned by a structural fingerprint test. Spec suite 39 files, 841 passed; tsc clean. Reverting any of 19 fix sites fails its reproduction test. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ease (astra 112b A)
Slug syntax is not a privacy boundary ("alice-smith" passes
isPublicCapabilityUrl), so a demand_aggregate now has to name a capability in
an approved public set, and has to name the release record it came from.
- BUILTIN_PUBLIC_CAPABILITY_URLS: the CSD urls compiled into @pcc/spec
(loadBuiltinCsds), filtered, sorted by code unit, frozen. That is 8 urls:
document-print-and-mail/v1 is a draft workflow CSD that loadBuiltinCsds does
not register and the package build does not ship, so it is not in the set.
- publicCapabilityUrls(activeKitCsdUrls): built-ins plus ACTIVE kits' csd urls;
throws on any entry that is not a public capability url.
- approvedSetDigest(urls): same construction as #365's approvedSetDigest, pinned
by a golden vector (also checked once against #365's real buildPublicRelease).
- DemandAggregateDTO.releaseDigest is required.
- opportunityDTOSchemaFor(urls) snapshots the set once; demand_aggregate needs
membership. OpportunityDTOSchema is built from the built-ins.
- demandAggregatesFromRelease(release, approvedUrls, asOf) rebuilds the DTOs and
throws unless the record's digest, approved-set digest, periods and
membership all hold.
- isPublicCapabilityUrl is documented as a syntax backstop, not a boundary.
The aggregate() fixture moves to a built-in capability, period 2026-08 and past
instants; the opportunity shape fingerprint is re-pinned (releaseDigest).
Agent: implementer-kilo
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FT8WYWkfig4KNcxtMqvMuj
… fail closed (astra 112b B) An empty primitive set was vacuously executable, and decl.self_attested (tier 0 only) could be presented as an executable tier-3 requirement, because executability only asked for live verifiers. - evidenceIsExecutable(tier, refs) runs the evidence lane's computeCsdEligibility with requireImplementedVerifier on the single tier: non-empty from tier 1, tierSupport, dependency closure, a Family-G primitive from tier 2, a non-decl primitive from tier 1, and live verifiers. Tier 0 with no primitives is the executable floor. - EvidenceRequirementSchema checks executable === evidenceIsExecutable(...), in both directions. Funded kinds still need executable evidence. - primitivesAreExecutable stays exported, documented as necessary, not sufficient; nothing in the schema calls it. - validatePrimitiveParams fails closed: only type (one string), enum, items (an object schema), properties, required and additionalProperties (false, true or an object schema, now validated) are evaluated; annotations are ignored; any other keyword, an unknown or missing type, a malformed keyword, or a schema that would mean "any value" returns false. required and properties use own keys only. - PRIMITIVE_PARAMS_KEYWORDS and PRIMITIVE_PARAMS_ANNOTATIONS are exported so the test walks every active primitive against the same set the validator uses. One active stub, telemetry.envelope_conformance, uses oneOf today; the test pins it, requires every live primitive to stay inside the grammar, and shows that stub fails closed. The evidence() test helper now states evidenceIsExecutable. Ports the 112b reproductions for HIGH 4a, 4b and 4c. Agent: implementer-kilo Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FT8WYWkfig4KNcxtMqvMuj
…r (astra 112b C) isSpdxLicenseExpression claimed SPDX validity but accepts only PCC's curated list, so real SPDX ids such as EUPL-1.2 and DocumentRef references were refused while the name said otherwise. - Rename it isAllowedLicenseExpression and remove the old name (pre-release). The doc now says: SPDX expression syntax over PCC's allow-list of license and exception ids plus LicenseRef-<id>; not a general SPDX validator; a real SPDX id outside the list and DocumentRef references are refused by policy; extend the list by PR. - validateKitCompleteness, KitCompleteness.missing and spdxLicense docs say "allowed license expression". The "license" gap id is unchanged. - Tests: EUPL-1.2 is refused as a policy, "MIT OR Apache-2.0" is allowed, and the module no longer exports isSpdxLicenseExpression. Ports the 112b reproduction for finding 2, fixed to the allow-list semantics. Agent: implementer-kilo Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FT8WYWkfig4KNcxtMqvMuj
…of describe (astra 112b D)
maskPayoutDestination("AB") returned the whole value, and the schema could not
tell a mask from a reconstructed short value. availability.describe could carry
endpoint text while the docs said availability "never" carries an endpoint.
- maskPayoutDestination trims, then: under 8 characters returns the mask alone,
under 40 the mask and the last 2, otherwise the first 6, the mask and the last
4. It reveals at most 25%; an EVM address (42) shows 6+4.
- MASKED_DESTINATION also accepts the bare mask. Its doc says the schema checks
the FORM only and cannot know the source length; the helper guarantees the
ratio.
- availability.describe refuses ASCII scheme:// text (any case) as a backstop.
The docs now say what is enforced: no endpoint or authority FIELD (strict),
describe is display text a consumer must never parse, fetch or execute, and
the other availability strings are length-bounded typed values.
- The operator-binding shape fingerprint is re-pinned (the mask regex changed).
Ports the 112b reproductions for MEDIUM 5a, 5b and the 5b control.
Agent: implementer-kilo
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FT8WYWkfig4KNcxtMqvMuj
A future demand period paired with a forged future asOf passed, because the only check was "the period closed before asOf" and asOf is caller-supplied. - MAX_AS_OF_SKEW_MS (5 minutes) is exported from opportunity.ts, with one shared helper, readTimeIsNotInFuture. Every OpportunityDTO kind refuses an asOf later than now plus the skew; so does OperatorBindingDTO for asOf and for every binding's lastSeenAt. An unparseable instant is refused too. A deadline is not restricted. - The docs say what this is: a bound on a forged future time, not proof that a time is true; the producer assigns read times from its own clock. - Fixtures already use past instants (the aggregate fixture moved in the public-demand commit). Times in the new tests are computed from Date.now(). Ports the 112b reproduction for MEDIUM 7 (the verdict's 2099-12 case). Agent: implementer-kilo Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FT8WYWkfig4KNcxtMqvMuj
…ded (astra 112b F)
The structural fingerprint unwraps ZodEffects, so a change to a superRefine (demand
privacy, funding rules, duplicate or NFC rejection, tier validation) moved no pin.
- Three corpora under __tests__/kits-corpus/, one per literal, each
{literal, cases: [{name, expect, value}]} of wire JSON: 90 opportunity, 67
operator-binding and 53 capability-kit cases. Every refinement rule has a reject
case that fails only because of it, plus accept cases; the rules from A to E are
included. Timestamps are in the past, except the cases that exist to prove a rule
refuses the future (year 2100) and one far-future deadline.
- The MEDIUM 8 block now checks: every case's verdict equals its expectation; one
lock table pins {literal, shape, corpus} per literal (corpus = first 16 hex of
sha256 over the parsed file); each corpus names its schema's literal; wrapping a
schema in a superRefine that refuses its first accept case flips a verdict; and
every refinement message a corpus reaches has a case that produces exactly that
one issue.
- The comment above the lock table says changing a pin under an unchanged literal
is the review-blocking act and that no in-repo test can stop a PR rewriting its
own pins: the merge-gate review is the control.
- The Versioning paragraphs in opportunity.ts, operator-binding.ts and
capability-kit.ts name the corpus.
Ports the 112b reproduction for MEDIUM 8: a superRefine-only change leaves the
fingerprint unchanged but moves corpus verdicts. The shape pins were re-pinned in
the commits that changed those shapes (releaseDigest, the mask regex).
Agent: implementer-kilo
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FT8WYWkfig4KNcxtMqvMuj
…r (astra 112b A) The pinned built-in list has 8 urls because this branch is behind master's 2d80818 (board N64), which registers document-print-and-mail/v1 in loadBuiltinCsds. The set follows the registry, so the pin fails by design when this branch merges master; the comment now says so and says what to add. Agent: implementer-kilo Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FT8WYWkfig4KNcxtMqvMuj
…ra 112b E) The tests accepted asOf = now + MAX_AS_OF_SKEW_MS, which only holds while the clock never steps backwards between computing the instant and parsing it. They now use 1 s inside the boundary; the refusal cases stay a minute beyond it. Agent: implementer-kilo Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FT8WYWkfig4KNcxtMqvMuj
…he release contract) Master carries painpoints' #365 (kit-demand.ts: PUBLIC_RELEASE_POLICY, isReleasePeriodClosed and PublicOpportunityRelease), which astra 112c asks demandAggregatesFromRelease to reuse. It also carries 2d80818 (board N64), which registers document-print-and-mail/v1 in loadBuiltinCsds. The one conflict-free consequence is planned: the built-in public set follows the registry, so its pinned list gains that url, in sorted position, here (the test said to do it in the merge commit). Spec 1181/1181 (48 files); package tsc and the contract test file's tsc exit 0. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zYzsSSFUHbPV5DNxssX4A
…e executability, module digests All three open findings were reproduced at a173743 first (scratchpad repro-112c: three failing tests plus a passing control, and a mutation trace for MEDIUM 8). CRITICAL 1 (demand privacy). demandAggregatesFromRelease now enforces #365's exact release contract, reused from types/kit-demand.ts (on this branch since the master merge): - the record's policy must be PUBLIC_RELEASE_POLICY's k and evidence floor exactly, and every aggregate must be counted at that floor (strict literals; the verdict's k 0 / query record is refused); - the period must be releasable under #365's rule, isReleasePeriodClosed: ended at least the 24-hour grace ago by this clock; - PublicOpportunityReleaseRecord is now #365's PublicOpportunityRelease. A demand_aggregate DTO's asOf must also fall after the period's close plus that grace, since no release can exist earlier. HIGH 4 (executability). evidenceIsExecutable checks the CUMULATIVE program, tier 0 through the target. Each tier gets the refs that support it and whose dependencies are satisfiable there (fixpoint), so it is the best assignment the refs allow. computeCsdEligibility's eligibleTier must then reach the target, with live verifiers. A ref that can contribute at no tier up to the target fails it. Payer approval alone is no longer executable at tier 2 or 3, because its tier 1 set is empty (the verdict's reproduction is a test). Positive tier 1-3 cases mark the stub ident.registered_key live inside a try/finally, because no tier 1-3 set is executable with today's registry. MEDIUM 8 (versioning). The lock table also pins the digest of each literal's own module, so any edit there fails CI until it is re-pinned. That includes a refinement whose effect lies outside the finite corpus (the verdict's reproduction now fails on exactly that pin). The Versioning docs list the inputs that live outside each module. Corpus: the payer-only accept cases become honest non-executable cases. New rejects cover payer-only executable claims and reads inside the grace; the demand accept cases move past the grace. The generator is deterministic: the binding and kit corpora came out byte-identical. Tests: spec 1185/1185 (48 files); package tsc and the contract test-file tsc exit 0. Mutations: 8 of 8 killed (grace check, policy, counted evidence, DTO grace, single-tier executability, non-contributing ref, dependency fixpoint, and the out-of-corpus refinement). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zYzsSSFUHbPV5DNxssX4A
…irement CRITICAL 1 (reproduced at cbc1c14): demandAggregatesFromRelease accepted a self-consistent release whose aggregates were in reverse code-unit order, a record #365's buildPublicRelease can never write. The reader now requires capabilityType strictly increasing in code-unit order (the order #365 sorts into), so the order carries no information. HIGH 4 (reproduced): the dependency pass silently removed a named primitive and then judged the reduced program, so confirm.execution_mode alone was executable at tier 0, and registered_key + execution_mode (no receipt) at tier 1 with the key live. Every named ref must now sit in some tier; otherwise the requirement is not executable. That rule subsumes the old "supports some tier" pre-check, which is removed. The tier-1 expectation that pinned the hole is now false. LOW: the header names every external input (csd/schema.ts, capability-kit.ts). Corpus: 3 new cases (97). LOCK re-pinned: opportunity corpus 4fb26628cccab46e, source 4deb00fd1332e7d0; shape unchanged. Spec 1187/1187, both tsc 0, mutations 11/11 killed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zYzsSSFUHbPV5DNxssX4A
This was referenced Oct 3, 2026
#348 (merged 15:23) and #397 both add exports to packages/spec/src/types/index.ts after ./ui-artifact.js, which is the only conflict. It is resolved as the union of both sides, verbatim: #397's capability-kit, operator-binding and opportunity exports, then #348's render-provenance export. Every other path that differs from 79a3330 (450 of them) equals master's blob exactly, so no file was auto-merged. Spec: 73 files, 2255 tests pass; both typechecks are clean. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zYzsSSFUHbPV5DNxssX4A
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
These are interface-only
@pcc/speccontracts for the kits lane (ledger R5/R6/R7/R8/R41/R45, product PX-13). The PR adds no routes and no storage. It is not for merge before wave D (steward ruling #3058).The contracts are v0, frozen for consumers: adk (R4), readmodels (PX-7), operator-ux (PX-11) and refvertical (R46) build against these shapes, and any change needs their ack on the bus first.
types/capability-kit.ts: Capability Kit manifest and identityCapabilityKitManifestV1is strict zod, and its references are:capabilityContractDigest, because a url alone is a mutable pointer;computeKitDigest = sha256(canonicalize(normalized manifest)). That is the same construction ascapabilityContractDigestand uses the single@pcc/speccanonicalizer. List order never changes the digest.parentKitDigestrecords forks and revisions.sha256:e05bb524…2527. Re-run them when N15 / fix(spec): canonicalize refuses values that have no JSON form #359 changes the canonicalizer.validateKitCompletenessseparates a reusable kit from a one-off listing. A reusable kit has an implementation, tests, an install recipe, a provenance recipe and a license. This is the L1 acceptance rule for kit-build bounties.types/operator-binding.ts: OperatorBindingDTO v0The shape was agreed with operator-ux (bus #2896 / #2944):
principal.identityStatusisself_asserted | proven.executorKinds, the bindings (each with akitDigestand a server-capped tier), and claim rights.moneyAuthorityis the literal"none". Execution authority is derived from bindings, never from the key's scopes.types/opportunity.ts: OpportunityDTO v0There are three kinds:
funded_offer,kit_build_requestanddemand_aggregate.fundedneeds an authoritative, server-verified source.toPublicOpportunityAggregatefields (type, band, as-of): no location, evidence or deadline, and no raw intents, priors or requester identities.Tests
/mnt/sparkbulk/pcc-lanes/wt-kits-spec)packages/spec: npx vitest run src/__tests__/kits-contracts.test.tspackages/spec: npx vitest runpackages/spec: npx tsc --noEmitThe tests cover:
Merge conditions (steward #3058)
Merging is the operator's call, and only after wave D opens.
Refs: kits reconciliation §0.4 K1/K3/K4 and §0.5.1; bus #2780 (refvertical manifest mapping), #2896/#2944 (operator-ux), #2607 (painpoints demand policy).
Round 3: astra 112b fixes, at a173743
Every open finding was reproduced at 072f9a1 first. The fixes are in 8 commits, written by a Sonnet implementer from my spec, then reviewed and mutation-checked by me:
opportunityDTOSchemaFor; the default is the built-in CSDs, and ACTIVE kits come viapublicCapabilityUrls). It carries a requiredreleaseDigest, anddemandAggregatesFromReleasechecks the record's digest, its approvedSetDigest (same bytes as feat(spec,demand-intel): kit-demand signal and fixed periodic public release layer (R44, PX-13) #365), its periods and its membership.isAllowedLicenseExpressionis an honest allow-list (renamed from isSpdxLicenseExpression).executablemeansevidenceIsExecutable: tier-eligible under evidence's computeCsdEligibility, with live verifiers.validatePrimitiveParamsfails closed.scheme://text.Evidence: spec 885/885, both typechecks clean, mutations 10/10 killed in my independent pass. Review pack:
112c-k-397-r3-a173743e.At merge with master, one pinned test (the built-in public list) gains
pcc://capabilities/document-print-and-mail/v1(2d80818) by design.Round 4: astra 112c fixes, at cbc1c14
Master was merged first (3f16596). It brings painpoints' #365 (
types/kit-demand.ts) and the 9th built-in CSD. Every open finding was reproduced at a173743 first. The fixes are mine:demandAggregatesFromReleasereads feat(spec,demand-intel): kit-demand signal and fixed periodic public release layer (R44, PX-13) #365's exactPublicOpportunityRelease:evidenceIsExecutableis CUMULATIVE. It builds a dependency-closed program for tiers 0 through the target, runs evidence's computeCsdEligibility with requireImplementedVerifier, and requires every tier through the target to be eligible. Payer approval alone is no longer executable at tier 2 or 3.Evidence: spec 1185/1185, both typechecks 0, mutations 8/8. Review pack:
112d-k-397-r4-cbc1c149.Round 5: astra 112d fixes, at 79a3330
Both open findings were reproduced at cbc1c14 first (3 failing cases, 2 controls). The fixes are mine:
Evidence: spec 1187/1187, both typechecks 0, mutations 11/11, opportunity corpus 97 cases (LOCK re-pinned). Review pack:
112e-k-397-r5-79a3330d.🤖 Generated with Claude Code
https://claude.ai/code/session_01FT8WYWkfig4KNcxtMqvMuj