Conversation
Four independent readers went over the capability-binding series, each finding handed to a skeptic told to default to refuting it. Fifteen findings, ten refuted, five survived. All five are mine and three are serious. Authorizing one brokered leaf authorized every leaf in the catalog. Composite provisions all share the broker's dispatch tool_ref by design, the leaf travels in the call's arguments, and nothing anywhere compared the two -- decide() never saw arguments at all. A run bound to the quantum leaf could invoke the EDA leaf, or a leaf nobody reviewed, through authorization it already held. The provision now records which argument names the subject, the client threads the call's arguments into the decision, and a composite refuses a subject it did not bind. A decision made without arguments cannot fall back on the dispatch tool's authority either. record_invocation takes the arguments too, so the governance record cannot disagree with the decision that admitted the call. lifecycle_tool_refs was the exact defect this series was removing, reintroduced by me. The authorization view read it; the two places computing the run's bound tool set did not. Every legal poll of an async subject was scored as an invocation of an unbound tool -- an audit finding, an adversarial-engine finding, a charge against unbound_invocation_rate, and CK-CAP-001 from the capability kernel, on the sequence the binding exists to permit. bound_tool_refs is now the shared projection and includes the lifecycle surface; the kernel matches a binding by its lifecycle refs too. The route probe accepted the kernel's own unreachable ::/0. Matching the destination alone matched ip6_null_entry -- loopback, RTF_REJECT -- which every host carries, so an air-gapped node with IPv6 enabled reported a path off the host and the retrieval capability became bindable there. That is the case my docstring claimed fails closed. Both families now require RTF_UP, no RTF_REJECT, and a non-loopback device. Two smaller, also mine. tool_registry.md still said an operator must grant the IBM Quantum scope or nothing binds; the presence filter I added later made that false. And the test named for asserting the witness runs before the device probe joined a str character by character, so no multi-character substring could match and it passed for every possible implementation. The refuted ten are not recorded; a finding that does not hold is noise.
output_schema_digest was the digest of {} for every Provider, for every tool,
for every version -- a field whose entire purpose is detecting schema drift,
carrying the same value everywhere and unable to detect anything. Not because
the shapes were unknowable but because no tool declared one: zero outputSchema
across all seventeen skill packages.
Declaring one is not a documentation change. The MCP library validates
structuredContent against the declared schema and refuses the call outright when
it is missing, and every handler here returned TextContent alone -- so adding a
schema without also returning structured content would have broken every call to
that tool. Both handlers now return the pair: the text keeps the exact bytes ARI
already digests, the structured copy is what gets validated.
Each schema is a union of the tool's success shape and its own failure shape,
and the two packages needed different unions. HPC reports failure as
{"error": {kind, message, retryable}}; coding reports it as {"error": "<string>"}.
A schema describing only success would have converted a scheduler failure into
an output-validation error and thrown away the message saying what went wrong --
the failure would have been reported as a schema problem. Neither union could be
assumed from the other.
The submit tools derive their schema from JobHandleV1 rather than repeating it,
because a hand-written copy is a second source of truth for the same bytes and
would drift the first time the contract gained a field.
One thing this nearly broke. The coding provider scrubs the real work_dir,
$HOME, username and hostname out of its serialized output; a declared schema
sends a second copy of every result to the agent, so returning the raw dict
would have pushed all of it straight through the boundary _virtualize exists to
hold -- the text clean, the structured twin carrying everything it removed. The
structured value is parsed back from the scrubbed text, and a test asserts that
rather than trusting it.
Verified through real MCP handshakes, not handler calls. The unit suites passed
throughout -- 108 and 47 -- while the library's validation runs only over the
wire, which is also how a missing import surfaced as a live discovery failure
instead of a green test. Both branches were exercised: success shapes returned
and validated, and the error unions asserted deterministically because provoking
each tool's own failure at runtime is unreliable.
Five tools still publish nothing: describe_environment, edit_code, job_cancel,
job_logs, job_result, job_status, probe_platform_capabilities. None is
classified into a capability, so none gates conformance; they are left rather
than done badly in bulk.
The repo venv holds x86_64 wheels, so on an aarch64 compute node numpy does not import and nothing measured there can run. The arch-specific venv is built on that node and is hundreds of MB of binaries -- a build artifact, not a checkout, like the two venv rules above it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
execution_modes.md said the epoch-boundary ari_rqgm -> simple_bfts downgrade "is audited and validated by the ConstitutionalKernel". No downgrade event exists anywhere in ari-core, rqgm_state.json is write-once, and validate_epoch_invariance raises only CK-EPO-001/002 -- neither looks at the mode. The guide was describing a reserved design as shipped behaviour. Says "not implemented" now, and the three downstream sentences that repeated "immutable except at epoch boundaries, downgrade-only" say the mode is fixed for the whole run, so the page no longer contradicts itself. en/ja/zh. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…wo commits Seven findings survived refutation. Two were latent in the schemas I had just declared and would have broken real work; two were regressions my own fail-open fix introduced; one was a claim my own test asserted and one path did not meet. slurm_submit declared JobHandleV1 and never returns one. SlurmClient.submit builds its own flatter bridge dict, and JobHandleV1 forbids extra properties while requiring five the bridge never carries, so every arm failed. The library would have refused each successful submission AFTER sbatch had queued the job -- the agent gets an error, cannot poll or cancel a handle it never received, and resubmits. I copied the sibling tools' declaration without checking that this one returns something else. It now declares the shape it actually produces, and a real submission through the full path returns job 267890, COMPLETED. oneOf was the wrong combinator in both packages. It demands exactly one arm match, and these shapes are not exclusive: a timed-out execution is a complete result that also carries an error string, so it satisfied both arms and was rejected. The timeout payload -- stdout, stderr, the execution receipt -- was destroyed and replaced by a schema complaint, after the timeout had already been paid. anyOf is what was meant. Then the two I caused fixing the composite fail-open. The subject gate applied to every decision, so list_tools -- which decides with no arguments -- filtered every composite out of the agent's visible tools, and lifecycle refs, which carry a job handle and never a leaf, could not satisfy a gate that demanded one: every legal poll refused, of exactly the asynchronous binding the lifecycle surface exists to permit. The gate now applies only to a real dispatch call, and dispatch always supplies a dict so an absent one unambiguously means visibility. edit_code's early return skipped the scrub. No host identity actually reaches the agent there today -- _edit_code is handed the agent's virtual work_dir, not the resolved one -- but it is in _WORKDIR_TOOLS and my own test asserted the structured half always comes from scrubbed text. Rather than weaken the claim I made the path meet it, and the test now checks every return instead of the one I happened to write. None of this was visible to 155 passing unit tests. The library's validation runs only over a real handshake, so the timeout and submission failures were reproduced by driving the actual protocol, and the submission fix by queueing a real job.
Both packages changed when the output schemas landed and again when the review fixes did, so their commit and package digests stopped describing them. The previous attempt at this staged nothing and committed nothing while reporting success; the gate caught the drift again, which is the only reason it did not ship that way.
…ct gate The gate exists so one reviewed leaf's authorization cannot carry every other leaf in the federated catalog. A direct binding on the same tool_ref defeats it: when the named subject is not bound the authorization view falls back to the direct binding, and a call reaching a leaf nobody reviewed is admitted under its authority. Not live today -- the broker entry classifies none of its own tools -- and an adversarial reviewer's finding on this was refuted on exactly that reachability ground, which is why it needed closing rather than filing: nothing prevented someone classifying `invoke` tomorrow and deleting the gate without touching it. Refused where the combination is written rather than defended against in the view, because a defence there would have to choose between honouring a real direct binding and honouring the gate, and a broker's dispatch surface supplying an ontology capability in its own right is not a thing that should be expressible at all. The lifecycle-tool half of the test took three tries to make honest. The first fixture had no lifecycle tool in the Provider Lock, so an older check refused first; the second classified it into a workspace-write contract, so the side-effect check refused first. Both passed for the wrong reason. It now classifies a lifecycle tool into a read-only contract it genuinely satisfies on every other axis, so the new backstop is the only thing that can refuse it.
…ts own making
The CUDA promotion recorded capability_contract_digest as a local hash of
{capability_ref, semantic}. That value was never the ontology's contract digest,
so the pin could not go stale when the contract moved -- it had never been bound
to the contract in the first place. The pin checker reads it as a mismatch
because it is one, and always was.
Read the ontology and record contract.contract_digest, refusing outright if the
ontology does not declare the ref. The sibling ToolUniverse promotion has done
exactly this all along; this script simply did not.
This does not repair the bundle already on disk. That one keeps its synthetic
digest until the provider is promoted again on an exclusive V100-class node.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ied against Both locks recorded capability_ref and stopped there. A capability claim with no contract digest cannot go stale: there is nothing for the contract to move away from, so a promotion stays green forever no matter what the ontology later says the capability means. That is the same defect the CUDA promotion had, arrived at by omission rather than by a synthetic digest. Resolve the digest from ARI's ontology at the one point that is both the writer and the verifier's expectation, so the pin is read on every verification rather than merely written once. The resolver is its own module because each promotion hashes its own source into promotion_verifier_digest, and putting it in the shared promotion module would move every provider's digest at once. The bundles already on disk record no pin, so they now fail verification. That is the intended direction -- they were never bound and could not be shown to be -- and it clears when each provider is promoted again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The launch paths fill blanks in the subprocess environment from a list of .env files, then fall back to the Settings key only when the slot is still empty. A value read out of ~/.env was therefore indistinguishable from one the operator exported, so a global dotfile nobody remembers writing silently beat the key configured moments earlier -- and beat it invisibly, because from the launcher's side both cases look like "a key is already present". Have load_dotenv_files report which names it introduced, and let Settings override exactly those. A key the operator exported still wins, which was the documented intent; a key that only ever sat in a file no longer does. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The temporary plans under docs/plans/ were the sole written home for a number of normative decisions, which is one of the reasons none of them can be deleted. This migrates what could be migrated honestly: 101 items across nine plans, each verified against the tree before it was written. Two things were deliberately not done. Designed-but-unbuilt contracts are written as gaps, never as behaviour -- a plan describing something the code does not do does not become true by being copied into a guide. And stale plan text was dropped rather than migrated, e.g. plan 01's claim that wrap_node_executor is identity in v1, which the shipped method has long since outgrown. The pass also corrected roughly ninety places where a permanent doc already claimed more than the code delivers. The largest: profiles were documented as a deep merge when _apply_profile reads four keys and silently discards the rest, and several pages carried "downgrade-only" resume language for a downgrade that is not implemented. en/ja/zh throughout; all six docs gates pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The package docstring called it "a FastAPI-style HTTP server" with a "uvicorn lifecycle". Neither library appears anywhere under ari/viz -- routes.py serves on the stdlib ThreadingHTTPServer, and ari/viz/v1's own docstring already says "no FastAPI/uvicorn, no new runtime". The two sibling modules contradicted each other, and the wrong one is the one a reader meets first. The only record that this was wrong lived in a temporary plan under docs/plans/, which is one of the things keeping that plan undeletable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A research contract requiring correctness emitted one hardcoded property,
"artifact-correctness". No shipped manifest declares it -- the three
registered harnesses declare numerical-equivalence, interface-conformance and
reproducibility -- so every correctness obligation resolved to no harness at
all, with no error and no warning.
Measured against the real catalog, before and after:
artifact-correctness -> 0 manifests, 1 unsatisfied
numerical-equivalence + interface-conformance
-> 1 manifest, 2 covered,
0 unsatisfied (coverage enforced)
Which concrete properties establish correctness is a statement about the
science, so it is declared in the property vocabulary rather than written into
this function. reproducibility is deliberately absent: the shipped manifests
offer it at validate and certify only, and a correctness requirement is raised
at screen, so demanding it would make every screen run unsatisfiable.
Unset falls back to ["artifact-correctness"], so a configuration without the
key behaves exactly as before.
THE OTHER HALF CANNOT LAND ALONE, and this is why it is not here. Making the
manifests declare artifact-correctness changes their manifest_digest, and
load_harness_catalog requires report.manifest_digest to equal it. So it needs
all three registration reports, evidence bundles and approvals re-minted --
and reports are minted from evidence now, which needs the correctness driver's
parity probe run on a clean tree and a maintainer's signature. This change
resolves correctness without waiting for that, and composes with it: when a
manifest does declare artifact-correctness, adding it to correctness_properties
is the whole edit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… bound none Every web-skill tool already declares a capability_ref in skill.yaml, and the alias table already resolves most of them to real contracts. None of it reached the binder: a provision is built from declared_capability_refs_by_tool alone, and that table was empty, so the whole retrieval surface was unbindable while looking fully annotated from every other angle. Four tools are classified -- the ones whose locked policy actually satisfies the contract they claim, verified against a real Provider lock rather than against the manifest's hint. Three are left out and the file says why: rerank is read-only with a model permission where the contract is workspace-write over network-read, so the alias asserts a mapping the loader would refuse; fetch_url and web_search have no contract, and inventing one to complete the table would admit an unprovenanced live fetch as a scientific capability. The two gates that make any of this mean something -- side-effect equality and permission coverage -- had no test. They do now, including the negative control that shows the refusals come from the policy and not from the fixture. The ja/zh references were several facts behind: they still described literature.search as unsuppliable and quantum.sample as unregistered, both since resolved, and carried nothing about the exclusive-node retirement or the compatibility-rule vocabulary. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every forgery demonstrated against this harness used the same two primitives: fork(), and reading /proc/self/cmdline to find the file the credited time is written to. The harness caught both after the fact -- a wall bound, a cross-role overhead calibration, a process-group reap -- but each of those is a check, and a check only refuses what someone thought to check for. The timed child now runs under Landlock, applied between fork and exec so it binds the child and everything the child starts; Landlock is inherited and cannot be dropped, so a forked writer is under it too. It is allowed the system libraries and ONE writable directory: the run's own scratch. What it denies is the point. /proc is not in the ruleset, so a kernel can no longer read its own cmdline to find the timing path -- both forgeries return early and score as what they are, honest naive loops, with no check having to fire. The problem directory is not in it either, so a candidate cannot read the frozen reference that is its own denominator. The helper is extracted from drivers/native_candidate_host, which has used it for the correctness harness's candidate process. The perf path had no sandbox at all. TESTED AS TWO LAYERS, deliberately. The detection tests now run with the sandbox disabled, because a defence that is only ever exercised behind another one is a defence nobody has tested: on a kernel without Landlock the checks are the only thing standing and they still have to work. A third test asserts the sandbox prevents the attempt. It records what it enforced AND what it does not claim: filesystem access control does not restrict fork, CPU or memory, and a record that overstates is worse than none. Best effort by default. On a kernel without Landlock the run proceeds and says so; a registered harness whose manifest demands isolation is a different question, refused by the driver rather than here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…opic LLMClient.complete() used to route this backend around litellm. The branch was lost in a merge and only the streaming guard came back, so a run configured for claude_code called litellm as `anthropic` and demanded an ANTHROPIC_API_KEY the CLI provider never needed. The configured backend was silently replaced by a different one -- the failure mode that looks like a missing credential and is actually a missing dispatch. That disguise is why this sat: the four tests that caught it failed with an authentication error, which reads as "no key on this machine" rather than "the backend is wrong". So the new test fails on the dispatch itself -- it makes litellm.completion raise, which is the assertion an existing comment in this module already made in prose and nothing checked. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
An adversarial pass re-checked the migrated text against the code, one auditor per document, told to default to "refuted" when it could not confirm. It found fifteen real errors across nine of the twelve documents audited; a second agent re-verified each before touching anything and rejected none of them. The migration's failure mode was the expected one: plans describe intent, and copying a plan's sentence into a reference manual turns a proposal into a promise. Two examples. rqgm_schemas.md documented self_audit.ban_recommendations and escalations as live governance outputs, but every check that could populate them is severity warn, so escalations is structurally empty and no ban recommendation can ever be produced -- the reader and the T19 wiring both ship, the producer does not. manuscript_complete_contracts.md described a governed reviewer as a gap the code has, when paper_dispatch.py takes the co-evolution branch and a governed reviewer is active from round zero. Corrections are in en/ja/zh where a translation exists. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The pin resolver imported ari.capability_binding.ontology directly, which is exactly the boundary a skill is not allowed to cross -- and it did not need to: ari.public.capability_binding already re-exports load_capability_ontology. Same loader, same digest, through the surface skills are supposed to use. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The catalog loader verifies manifest_sha256 only, so a package edit that leaves the manifest alone passes silently and the commit and package digests quietly stop describing the code. These pins are what make that visible. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
file_formats.md sourced the "both keys must agree" rule from docs/plans/ari_rqgm Task 02 -- a permanent reference depending on a document whose whole purpose is to be deleted. The rule now lives in the execution-modes guide, in the interlock table, so the reference points there instead. That was the last docs/plans/ citation anywhere in the permanent docs. en/ja/zh; check_doc_links reports 0 broken links. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The commit that added the sandbox said it "records what it enforced". It did
not. sandbox_record() had no caller anywhere, so nothing carried it, and a
comment inside preexec_fn told the reader that "the record above" would show a
failure -- there was no record above. A child whose restrict_to raised ran
UNPROTECTED with nothing anywhere saying so.
That is the exact defect this module spends its length guarding against,
written into the guard, in the commit claiming to have closed it. Found by
being asked a third time whether everything was solved.
The decision is taken once now, in the parent, from one probe:
- if this kernel CAN enforce isolation, the child MUST -- preexec_fn no
longer swallows, so a failure kills the launch;
- if it cannot, no attempt is made and the record says the run was
unprotected, rather than leaving absence to be inferred;
- either way the status travels with the measurement that used it, so the
record and the launch cannot disagree. NativePerfReportV1 carries it.
A launch that could not be isolated is typed as a substrate failure. CPython
replaces a preexec_fn exception with an opaque "Exception occurred in
preexec_fn.", so an untyped one would reach the evaluator and be scored as a
bad kernel.
The detection tests simulate a kernel without Landlock by changing what the
PROBE reports, since breaking restrict_to now exercises fail-closed instead --
which is the other behaviour and has its own test.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…erified The bundle on disk claimed ari.quantum.sample.local-ideal/v1 and recorded no contract digest, so nothing could notice the contract moving underneath it. The promotion now resolves that digest from the ontology, and this is the first bundle re-promoted through it: the lock carries sha256:0abe3edb… and the pin checker reports it bound rather than unbound. Nothing else about the identity moved. Re-running against the same pinned environment reproduced the same Bell counts and the same golden and replay fixtures byte for byte; what changed is the capability pin, today's capture date, and the digests that cascade from both. The lock digest moved with it, so the test and the six reference pages that quote it move too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The bundle lives inside the package the catalog pins, so promoting it again moves both the commit and the package digest. Leaving them stale would mean the pins stop describing the code, which is the exact silence this check exists to break. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Nothing in the repository declared kind: benchmark, so the
performance-regression slot that six knowledge-skill import profiles require
was reserved and empty, and the driver built to fill it was unreachable:
resolution is keyed on driver revision and no manifest named one. The driver
shipped; the harness did not.
benchmark + target_kinds ['benchmark-submission'] + accepts_external_target
false. models.py forbids a benchmark claiming external target coverage and the
resolver confines a non-external benchmark to {model, agent,
benchmark-submission}; both are coherent -- a benchmark scores a SUBMISSION --
and a candidate kernel handed to one is exactly that. No rule was relaxed to
make this fit; what changed was the label, in the commit that gave each
requirement the target kind its property implies.
The oracle slot pins the PROBLEM, whose digest covers the contract header, the
frozen driver, the reference, the seed and both negative controls -- so a
change to any of them is a re-registration. The dataset slot pins which sizes.
Verified: the manifest's self-pin matches, and NativePerfDriver.prepare accepts
it -- the problem pin, the case-set pin and the driver digest all agree. It is
NOT in the catalog: a row belongs there only once a registration report earns
it, and that report is minted from evidence a compute node has to produce.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
I wrote it to require the pinned commit to equal the one registration runs at. That is circular: writing the pin changes the manifest, which changes the commit that contains it, so no manifest could ever pass. The first real registration run failed on it -- 12/15, and one of the three was my own gate. The byte-level guarantee was never this field's job. ``prepare`` already refuses when the driver digest does not match the code that will run, exactly and by content. What the commit pin is for is PROVENANCE: where to check out to obtain those bytes. So the gate asks whether it names a commit this repository has and one the registration descends from. A pin naming nothing, or naming a commit off this history, still fails -- which is what the shipped reports would do, since theirs is regex-checked and compared to nothing. The performance manifest also inherited the correctness manifest's stale pin when I derived it. It now names the commit that last changed the driver source its digest covers. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The catalog has a fourth entry and its first non-verifier. Everything it carries was measured rather than asserted. The registration ran from a clean worktree at f1db2dd on an EXCLUSIVE aarch64 compute node: the parity probe three times, 15/15 gates, decision eligible-for-verified. Clean control 1.00593 at spread 0.0411, run-to-run spread 0.0141 over three runs, both negative controls failing for different reasons -- slow on the ratio, wrong on the residual bound. WHERE IT RAN IS PART OF THE RESULT, and the evidence bundle says so. The same commit and the same clean worktree scored 13/15 on an exclusive x86 64-core node, where the clean control did not resolve (spread 0.1648 against the 0.1 the instrument is read at). A first attempt on the shared login node reached 0.589. The bundle records the node class for that reason. The approval is signed 'kotama', authorized in this session, and its authorization_basis says what the maintainer actually saw: the assistant's report of the evidence, not the raw artifacts -- which are pinned in the bundle so a later reader can check them independently. A basis claiming an artifact review that did not happen would be the same defect this whole registration path was rebuilt to remove. Two test expectations moved because the shipped state moved: the catalog is no longer exactly three correctness harnesses. And the resolver fixture now pins a REAL commit, because the source-pin gate checks ancestry against the repository and a synthetic sha names nothing -- the fixture was passing on a gate that could not have been satisfied by anything real. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
90 shipped Python files cited docs/plans/** by path in comments and
docstrings. Those plans are temporary and meant to be deleted, so every
citation was a dangling reference waiting to happen -- and collectively
they were one of the reasons the plans could not be deleted at all.
233 citations now point at the permanent docs that carry the same rule,
each one checked by opening the target and confirming it actually says
what the citation stood for. Plan section numbers ("plan 04 section 5.4")
are replaced by the permanent document's own section names, since a
section number survives only as long as the plan does.
35 citations were deliberately LEFT ALONE. Those rules have no permanent
home yet -- the legacy Settings default values, the api-key length and
"test"-substring heuristics, the bucketed runtime path layout. An honest
dangling citation beats a confident wrong one, and writing those rules
down is separate work.
Behaviour is unchanged: comments, docstrings, and three pydantic Field
descriptions that had the citation inside them. 1863 passed, 3 skipped;
public-API, skill-manifest, metadata and MCP snapshot contracts all green.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
WORKFLOW.md documented "Reproducibility Check (ReAct)" as a four-step Reason/Act/Observe/Reason loop inside a tool called reproduce_from_paper. That tool does not exist: the name survives only inside tests, one of which asserts the error string "Tool 'reproduce_from_paper' not found". What ships is a chain of workflow.yaml stages over four real functions in ari-skill-paper-re/src/server.py -- fetch_code_bundle, build_reproduce_sh, run_reproduce, grade_with_simplejudge -- with the LLM appearing in exactly two of them. Scope note: this is separated from 110ec4f on purpose. That commit repointed docs/plans citations; this file had none, so the rewrite fell outside what was asked for. It is correct, but it is its own decision -- revert this commit alone if you would rather keep the old text. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The three correctness harnesses have been REFUSED since their driver digest changed: prepare compares it and they still pinned the old one. Repinned. The gates could not have passed them either. They were written against the performance probe report shape, so a correctness driver -- whose probe reports per-family verdicts -- could not satisfy a gate it genuinely passes. Both drivers emit one common vocabulary now: a clean control and a list of negatives. A gate should not have to know which driver answered it, which is the same correction as giving each requirement the target kind its property implies. And the negative-control gate stopped demanding two. Two failing the SAME way cannot tell a wrong answer from a slow one -- but that is a question about a stopwatch, and a correctness verifier has one kind of negative to offer. All must fail; distinctness is demanded where a driver supplies more than one. The performance driver refuses to probe when one of its two is missing, so the strength stays where it belongs. Stability likewise. A deterministic verifier has no spread, and demanding one would make it permanently unregistrable; what repeating it establishes is that it repeats, so the clean-control answers must be IDENTICAL and a difference is the finding. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
They had been REFUSED by prepare since the family migration changed their driver digest. The pins were not quietly rewritten at the time: a signature covers what was signed, and re-pinning alone would have made three attestations describe code nobody approved. So they were re-registered. Three parity-probe runs each, at commit 67e348c on a clean worktree: 15/15 gates, eligible-for-verified, all three. Fresh reports, fresh evidence bundles pinning the artifacts by path and digest, fresh approvals signed kotama with a basis that says what the maintainer actually saw -- the assistant report of that evidence, not the raw artifacts. The catalog now loads four registered harnesses, every one of them holding an approval over a report whose gates were computed. Two test expectations moved with the state. The resolver fixture emits the common control vocabulary. And the test asserting these harnesses REFUSE was inverted: it documented a transitional breakage, and the breakage is repaired, so it now asserts the pins match the driver that exists. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
One set answered two questions. `covered_paths` is what the hook consults to decide whether a commit touches anything that could invalidate a pin, and the manifests belong in that answer -- editing one is exactly when the pins want re-checking. The dirty checks then reused the same set to ask something else: which files a pin is computed FROM. A manifest is never one. It is what a pin is written INTO, and its own bytes are bound by `manifest_digest`. That inverted the signal rather than adding noise to it. Re-pinning REQUIRES editing the manifest, so `repin` refused the one act it exists to perform and had to be run from a clean checkout to write a pin at all; and `check` printed "these answers are about the working tree and not about any commit" on every commit that touched a manifest, which is most of the commits this surface sees. Loudest where it carried no information, and where a real instrument file WAS dirty the same line said nothing new -- it was already printing. `pin_input_paths` is now the narrower set and the dirty checks use it. Measured after the split: a dirty manifest alone leaves `check` silent, a dirty `sandbox.py` makes it say so, and the two sets differ by exactly the five shipped manifests. The test asserts that difference rather than a count, so a sixth manifest does not need it updated and a file dropped from the digest functions still fails.
Plan 20 section 8 says "The following list is normative. The parenthesized
name is the required test or parameterized case ID", and names one for each of
its sixty-eight criteria. Ten of those names exist. Everything else that is
covered is covered under a different name, so plan 18's criterion 9 -- "Task 20
criteria 30-58 and 60-62, 64-68 pass" -- fails on a strict reading for naming
alone. I had dismissed that as stale design naming; the plan calls it
normative, so the dismissal was not mine to make.
Renamed only where ONE test binds ONE criterion, because a normative id on a
test asserting something narrower is worse than the wrong name: the name then
vouches for coverage that is not there.
8 test_skill_body_digest_mismatch (was ..._blocks_composition) -- the
admitted body_sha256 is re-checked at compose_knowledge_instructions,
which is where a Knowledge body is used, so a body edited after admission
never reaches a node's prompt.
11 test_instruction_identity_skill_hashes (was ..._includes_skill_and_all_
lock_digests) -- asserts identity.ordered_knowledge_skill_hashes off the
epoch lock. The old name claimed the three lock digests as well; those are
schema-pinned fields of InstructionCompositionV1 and this body never
asserted them, so the new name is the narrower and truer of the two. It
does NOT bind criterion 64, which wants them in node provenance.
17 test_binding_lock_determinism (was ..._byte_identical_for_permuted_input_
order) -- one requirement, snapshot and environment mint one Binding Lock,
stated as invariance under the order the provisions arrive in, with the
request digest asserted equal first.
46 test_benchmark_kind_separation (was test_benchmark_cannot_cover_arbitrary_
artifact_requirement) -- drives the _coverage branch that refuses a
benchmark manifest with no external target for any atom outside
{model, agent, benchmark-submission}.
67 test_no_production_eval_import (was test_no_production_module_imports_the_
evaluation_harness) -- its own docstring already said "this is the
assertion the criterion names": the ast scan over the whole of ari/ with
the harness's own tree excepted.
TWO OF THESE COLLIDE WITH A NAME ANOTHER PLAN LISTS. Plan 17 section 14 lists
test_binding_lock_is_byte_identical_for_permuted_input_order and plan 18
section 15 lists test_benchmark_cannot_cover_arbitrary_artifact_requirement
among their planned tests. Neither list is declared normative and neither
plan's completion criteria cite it -- both defer to Task 20 section 8 instead
(17 section 15 item 8, 18 section 16 item 9) -- and the tree already deviates
from those lists in adjacent entries (..._weaker_harness against the real
..._weaker_method, test_baseline_lock_is_immutable_and_revision_is_monotonic
against the real test_baseline_lock_and_revision_are_monotonic). The normative
list wins, and no plan file is edited.
NOTHING WAS CREATED TO CARRY A NAME. Where nothing binds a criterion it stays
uncovered and unnamed: a test that exists and passes vacuously under a
normative id would make plan 18's criterion 9 read as met when it is not.
The capability-binding file is staged as this one hunk only; a concurrent
session is writing criterion 27's test in the same file.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzZuTFFv37eeHja2NY4kqr
The previous commit said re-pinning requires editing the manifest, so the refusal fired on the act the surface exists to perform and a pin could only be written from a clean checkout. A peer sharpened that further: the loop the tool PRINTS -- "Commit them, then re-run" -- was said to be guaranteed to hit it. Both are wrong, and neither of us ran it. Reproduced at the commit that introduced the refusal, on a worktree with a deliberately staled pin: repin -> commit -> re-run "pins: already current", 15/15 gates repin -> re-run without committing REFUSED The printed loop, followed as printed, does not hit the refusal. What does is a manifest already dirty when `repin` is invoked, and the path that reaches it is editing a field this surface does not manage: `source_full_commit_sha` is not a derived pin, so moving it by hand is the ordinary way to arrive holding a dirty manifest and be refused for it. That is what happened here, twice, and it is narrower than "the tool blocks its own procedure". `check`'s note keeps its account unchanged, because that half reproduces: it appears whenever a manifest is dirty, which is exactly during a re-pin, and adds nothing when an instrument file is dirty because the stale-pin lines are already printing. The split itself is unaffected -- a manifest is still never an input to a digest. Only the story about how often the wrong set was reached, which was told twice without being run.
Plan 20 criterion 27 names CK-CAP-016 and nothing produces it. The only caller that sets `provider_description_effective` is the offline KCA probe, which asserts the boolean itself, so a sizing pass read the gap as a missing producer and put the repair at a schema migration: a description digest on LockedToolV1, compared live against locked, plus regenerating every lock. That would have measured drift. The criterion is about effect. Tracing the path shows no description reaches a place where authority is decided, in any of the three places a description lives, so the honest close is a pin rather than a producer -- and a drift digest would have made an untrusted free-text field lock-bearing, which is the opposite of why it is excluded today. The pin drives the production chain twice -- discovery, SKILLS.lock, Provider catalog, Binder, authorization view, dispatch -- and compares whole serialized artifacts, so a description that reached any authority input surfaces without the test naming where to look. The injected text does reach the model's tool list verbatim, which is what makes the refusal downstream worth stating. All three channels are driven, because each is excluded by a different mechanism and one guard would have proved nothing about the other two: live tools/list text, manifest text, and a federated leaf's descriptor, whose four free-text fields are written outside this repository. The two identity-bearing channels move their supplier's identity and nothing else, and an edit nobody re-registered is refused by the manifest pin and by the re-derived broker catalog digest. Every compared artifact carries a control that moves it for a real reason, so none of the equalities can hold by being unable to differ. Verified red on removal at each of the four doors: folding the text into the runtime tool identity, into the locked policy, into the resolved manifest policy, or into a composite provision each fails the test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzZuTFFv37eeHja2NY4kqr
…g so Two commits ago this file said the note "adds nothing new when a real instrument file is dirty, because the stale-pin lines are already printing". That is a reason to delete it, and it is wrong in the one state it exists for. A peer caught it; reproduced here rather than taken on description. With `sandbox.py` edited and the performance manifest pinned over those dirty bytes, `check` prints: hpc_gemm_problem_correctness.yaml: driver.sha256 note: 1 file(s) a derived pin is computed from are uncommitted, ... 1 manifest(s) pin a digest the code no longer has The performance manifest is ABSENT. It reads current, because `check` recomputes from the same working tree the pin was computed from, so the pin matches the dirt. Every other manifest is covered by a stale line; that one is covered by nothing but the note. And it is in the worse state of the two -- a pin no checkout can satisfy, rather than a stale pin, which is detected everywhere. So the note is loud where it means nothing and is the ONLY signal where it matters, which is the opposite of redundant. The disposal stays as built: silent on a dirty manifest alone, firing on a dirty instrument file, and counting the instrument files rather than the manifests. Third correction to the same paragraph. The first two were written without running it; this one is what running it says.
This file was written after a history rewrite orphaned the source pins two bundles cite. It named three fields and three globs, so it found what it was told to find. Applying a teammate's rule -- derive the coverage, do not restate it -- it now walks every shipped artifact and takes any key whose NAME says it holds a commit. It immediately found five citations the enumeration never looked at, in evidence/production_e2e/, and all five are unresolvable. So the gate written for this defect did not cover the place the defect was living. AND THE DEFECT IS MINE. 361a85d7 was a commit of this branch. My rewrite moved every hash and the reflog expiry and `gc --prune=now` that followed removed the original, so a retained end-to-end record now cites a commit this repository does not have. I reported that purge as verified five ways -- orphaned blobs gone, 61 refs unchanged, HEAD unchanged, every worktree valid, fsck silent. All five were true. Not one asked whether a shipped artifact CITED a pruned commit, which is the question this file exists to ask and could not, because it was looking at three fields. IT IS NOT REPAIRABLE, and that is recorded rather than worked around. The rewritten equivalent 97107af is reachable and identical in tree, but both records are digest-bound over their own contents, so editing the field would forge them, and four test modules read them. Re-running a production e2e to repair a provenance field is not a repair, it is a different run. SO THE SPLIT IS DERIVED, NOT EXEMPTED. Live artifacts are whatever the catalog's entries name, plus the evidence bundle's siblings; a retained record is one the catalog does not name, which is the distinction the repository already draws -- test_harness_catalog_revision calls production_e2e "the frozen record of a past run". Live pins must be reachable. Retained pins are pinned: the unresolvable set must be exactly the loss recorded here, so a second rewrite that takes a different commit turns this red instead of inheriting an exemption. Both halves mutation-checked: emptying the recorded set fails the retained test, and pointing a live bundle at the lost commit fails the live one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…eed the open set Two guards from this round's own work, both found by its read-only audit, both the shape this repository keeps producing: a test that restates a subset where the property is what matters. CRITERION 11 WAS VOUCHING FOR COVERAGE THAT WAS NOT THERE, which is the exact artifact the round was warned against. Plan 20 §8.1 item 11 reads "Node instruction identity contains ORDERED Skill hashes", and the test renamed to its normative ID asserted `ordered_knowledge_skill_hashes == (one_hash,)` against a fixture admitting ONE Skill. A 1-tuple compares equal under every ordering, so the assertion held for a composer that sorted, reversed, or ignored the lock -- and the normative name then said the criterion was met. Two Skills now, in different composition slots, PROPOSED in the opposite order to the one the lock admits, so an identity echoing the request comes out wrong. The second body is chosen so its digest sorts BEFORE the first: with the original text the lock's order and lexical order coincided and the sort-discrimination assertion could not fail, which is its own version of the same defect. Mutation-checked: wrapping the composer's `order` in `sorted()` turns the test red. THE BROKER'S UNTRUSTED-TEXT SET WAS FOUR NAMES. `load_brokered_catalog` validates no descriptor keys and `_composite_provision` reads named keys off a plain dict, so the set of fields a third party can write into a leaf descriptor is OPEN -- and a fifth would have been uncovered. The injection is now derived: every string-valued descriptor key the mechanism does not read, plus the three container shapes a broker really uses, plus a key no descriptor has yet. Twelve fields instead of four, and a floor that fails if the inventory stops arriving rather than passing on an empty set. The boundary is stated rather than left implicit. List-valued fields are excluded because they are REFERENCE sets -- `source_ids` names sources the catalog cross-checks -- so appending to one adds a dangling reference, not free text, and the refusal that produces would have made the test pass for a structural reason with nothing to do with a description. Measured: the first version of this change did exactly that. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The three native correctness Harnesses were the last whose registration evidence
declared network_isolation from the REQUEST with nothing anywhere to derive it
from, and the gate that reads the observation skipped all three.
WHAT WAS ACTUALLY MISSING, after two wrong readings of my own. Not a schema
field, and not the isolation: this family runs a candidate in an isolated CHILD,
and `_restrict_candidate_filesystem` fails closed -- Landlock unavailable raises
and the case fails -- so a native candidate never runs unrestricted. That is a
stronger guarantee than the perf path, which records filesystem_isolation: false
and continues. What was missing is that nothing was RECORDED, and the network
was never observed at all.
THE OBSERVER IS WHOEVER LAUNCHES. A family verifies a Callable and never
launches, so it cannot know what the candidate ran under; the worker spawns the
isolated host, so it can. The child observes and returns it in its envelope, the
worker collects it across cases and RE-CREATES the report so report_digest
covers it, and the driver carries it into the attestation beside the oracle. The
filesystem entry is a precondition rather than a finding and is recorded anyway,
so a reader does not have to know the host fails closed; the Landlock ABI is the
one negotiated rather than the assertion that some Landlock was.
THE RESTRICTION PROVED ITSELF TWICE WHILE I WROTE THIS. Importing the probe
lazily beside its first use gave "Permission denied: .../assurance/sandbox.py",
and hoisting only that import gave the same for .../python3.13/socket.py. The
observation is taken BEFORE the restriction: Landlock does not touch a network
namespace, so before and after are the same answer and only one is reachable.
TWO TESTS PINNED THE EXACT SHAPE OF A RESPONSE and failed on a key they are not
about -- the child's envelope compared whole against {ok, result}, and the
worker's output compared whole against a two-key stub. Both now assert their
claim: that the candidate ran restricted and returned the right answer, and that
a scientifically wrong candidate leaves a completed process with a fail verdict.
The worker's stub becomes a real report, because the worker now re-creates one.
The report schema and both driver digests move, so the three manifests need a
re-pin and their bundles need re-earning; that is the next commit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…isolation The native driver's bytes moved when the isolated child started reporting what it ran under and the worker started attaching that record to the report, so each manifest named bytes the code no longer has and prepare() would have refused every run. Their evidence and signatures are void until re-earned by RUNNING the controls. That is what makes the observation appear in a shipped bundle rather than only in the code that takes it, and it is what stops the network gate skipping these three. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Criteria 50, 58 and 62 of Task 20 section 8 had behaviour in the tree and no test carrying their normative id. Two of the three had a test that stopped one step short of the criterion. 50 -- resume does not resolve against the latest Harness catalog. The dedicated test proved the published record cannot be exchanged for a newer one. That is not the criterion: a resume that re-entered the resolver and happened to keep the old bytes satisfies every assertion it made. Renamed to `test_resume_pins_harness_snapshot` and extended into the seam a resumed process enters -- `admit_from_checkpoint` with the newer catalog on disk and the admission builder wired to fail if it is called at all -- then reads back the Harness view the resumed run would verify against. The identities compared are derived by diffing the two admissions over `KCARunAdmissionV1.model_fields`, floored against arriving empty, rather than listed here. 58 -- the claim-evidence hard gate and the program verifier are two independent hard gates. Nothing asserted independence; the existing decision test varied the claim gate only while the assurance gate was `not_required`, which is the one configuration in which the question cannot be asked. Independence can be lost at three places and is now bound at all three: the decision (neither gate's pass rescues the other's fail, and an unknown certification is a failed one), the evidence (neither gate's report digest or reason code appears under the other), and the code, by scanning every module of both packages for an import of the other with the scanner's own ability to see a dependency asserted. 62 -- Harness execution does not depend on agent free tool choice. Half of it sat in a CLI test and half in an MCP test, and neither reached the verifier. The authority half is read off the whole capability matrix rather than a named role; the surface half takes the agent Provider's tools from its own `list_tools` and drives each one from its own input schema with `FixedVerifier.run` replaced by a tripwire, then fires the tripwire deliberately so "nothing executed" cannot mean "nothing could"; the execution half hands the verifier the manifest a caller chose, a lock the Harness is absent from, and a driver that rewrites the locked command. Every claim was proven by deleting its mechanism in a shadow copy and watching the test go red -- four mutations for 50, four for 58, six for 62. Criterion 50's test is currently red on this branch for an unrelated reason: the shipped Harness catalog does not load, because a manifest was re-pinned without its registration report being re-earned. It is green, and its mutations red, against the catalog as it stood one commit earlier. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three of Task 20 section 8's criteria had behaviour in the tree and no test carrying the id the plan declares normative. Two of them had a test that stopped one step short of the criterion, and one was covered on one of the two channels the system actually has. 42 -- an Evaluator/Reviewer claiming a fail as a success creates governance evidence. CK-HAR-019 was tested at `_kca_reports_for_node`, one level below the run loop, and nothing asserted that the finding is WRITTEN anywhere: the audit append could have been deleted with the suite green. `test_fail_misrepresentation_evidence` enters at `run_per_node_kernel_check` against a clean admitted baseline Lock -- so an honest node raises nothing at all and every code that appears belongs to the misrepresentation -- and reads the persisted `kernel_report` entry back off the immutable audit log. Both shapes of the override predicate are exercised, because an override lands on either the aggregate status or the frontier class and each hides from the other, and the `audit` posture case separates evidence from enforcement: the finding is still recorded where it is not acted on. The system has a SECOND channel for the same act, and a guard over one of them would have been a guard over half the criterion, so the test also drives `_assurance_contradiction_findings` and enumerates the adversary types that turn the accusation into evidence refs out of `ADVERSARY_SPECS` rather than naming them. 43 -- an uncertified result cannot reach final publication. The lane classification was tested; the publication DECISION was not, and the pure `build_publication_decision` test hands it `assurance_passed` as a literal. The publishable-build fixture now takes an assurance posture and one Attestation, so the whole path runs -- Attestation on disk, exploration snapshot, manuscript builder, readiness evaluator, `finalize_runtime_publication`. The certified control is asserted to publish with the assurance gate PASSING and naming that Attestation's own bytes, because "blocked" is otherwise consistent with a pipeline that blocks everything and "publishable" with a gate never required. A screen-tier Attestation and no Attestation at all each block, with every unrelated gate still passing. 57 -- the published claim's target is the certify Attestation's target. Same two runs, differing only in the artifact the Attestation is about: same node, same verdict, same tier, same property results. A certification of a different artifact stays visible as `stale` evidence rather than vanishing, and the final decision blocks. Every claim was mutation-proven in a scratch copy: removing the override predicate, removing the audit append, and removing the contradiction findings each turn 42 red; dropping the certify-tier conjunct or pinning `assurance_required` false turns 43 red; dropping the target comparison turns 57 red. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzZuTFFv37eeHja2NY4kqr
…it fires Task 20 section 8 criteria 31, 36, 37, 38 and 65 existed only as one case each of the catalogue-wide severity parametrization, where a single name would have vouched for sixty rules. Each now has a dedicated test under its normative id, and each states its rule once and then reads the places production applies it out of the source, because the repeated defect here is a guard written for a real rule that covers part of where the rule lives. That is not hypothetical for criterion 37. The first version derived the references an Attestation target must agree with from the comparisons validate_attestation performs; deleting the current-candidate half of that comparison shrank the derived inventory to match and left the test green. The inventory now comes from the function's SIGNATURE, which cannot shrink when a check is deleted, and every production call site is checked for handing it an independently obtained current target rather than one it already compares. - 31: seven routes refuse a Generator changing the required Harness, its tolerance, its oracle pin or the Lock -- the whole K/C/A resource table (exactly one non-read grant, and the Kernel blocks every other mutating pair in every tier), the producer literal, every _digest field the Lock entry and the Verification requirement pin, a SELF-CONSISTENT Lock a resumed run reads back as plain JSON, a revision dropping a required Harness, and write-once. - 36: a tolerance that moves is refused at all four layers that compare one, the Kernel's two producers raising one code under two rule ids. - 37: refused by the procedural validator, the Kernel, the Evidence Clerk (both comparisons, the envelope one isolated so the digest arm cannot answer for it) and the manuscript snapshot, where nothing raises. - 38: refused for every Lock pin the model carries, by the Fixed Verifier before one can be minted, and for a genuine re-presentation of a document that is still internally valid. - 65: driven through the production per-node fan-out, each artifact superseded ALONE, each lighting exactly one report context -- with the context set the fan-out emits as the axis inventory rather than a list of three. No CK code is named in an assertion: each finding is the difference between a coherent state and the same state with one field moved, so deleting the rule empties the difference. Every claim was mutation-proven in a scratch copy: 26 single mutations red, and the three that stayed green are redundant pairs or a documented fallback, each red once the redundancy is removed too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzZuTFFv37eeHja2NY4kqr
Task 20 section 8 criteria 45, 49, 51 and 64 get a test under their
normative id in a new suite, and 49 turns out to name a real gap rather
than a missing assertion.
Every scalar digest field in the Knowledge/Capability/Assurance contracts
already carried Field(pattern=SHA256_DIGEST_PATTERN). The anchors living
inside a tuple or a dict did not, so
HarnessPropertyResultV1(covered_atom_digests=("a" * 12,))
was accepted, and a truncated compatibility identifier could stand in for
an anchor the Kernel compares. Two of them -- attestation_digests and
skill_snapshot_digests -- sat directly beside a sibling field whose own
validator did check the format, which is the shape of a guard that covers
part of where its defect lives. The fix is a Sha256Digest alias carrying
the same pattern, applied at every such field, so the constraint is
declared where it is read.
The tests derive their inventories instead of restating them: the anchor
set is walked from the three ari.public K/C/A surfaces; the Kernel's
scientific blind spot is read off the result model's own free-form payload
annotations and its executor blind spot off builtin_driver_map(); the
compatibility path's artifact names come from the module that publishes
them and its node fields from the two bridges' ASTs; and the node
provenance compared is whichever identities the run admission and the Node
dataclass share. Each carries a floor that fails if the derivation ever
returns an empty inventory, and each was proven to bind by removing the
mechanism and watching it go red.
Criterion 68 is deliberately left uncovered; see the notes with this work.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzZuTFFv37eeHja2NY4kqr
…that had moved The harness catalog did not load: `load_harness_catalog` raised "Harness registration report differs: hpc/gemm-correctness". Three of five rows -- gemm, spmm and stencil correctness -- shipped a registration report AND a registration evidence bundle whose `manifest_digest` back-reference no longer matched the manifest beside them. Bisected to 575502d, which re-pinned the three manifests without re-earning what describes them. Measured rather than assumed: all 21 failures in the full suite (10 failed, 11 errors of 6679 collected) traced to that one defect, across five test files, with identical counts at 575502d and at HEAD. Nothing else was wrong. Re-earned through the signed re-registration path, four controls per family: hpc/gemm-correctness clean=pass negative=fail runs=4 gates=15/15 hpc/spmm-correctness clean=pass negative=fail runs=4 gates=15/15 hpc/stencil-correctness clean=pass negative=fail runs=4 gates=15/15 All five rows now have matching back-references, cite four or five real attestations, and none cites its own registration report. THE ROOTFS WAS VERIFIED BEFORE IT WAS USED, and this is worth recording because the surface does not do it. `--container-rootfs` is read to build the licence inventory that goes into every manifest, and `promote()` checks only that the path is a real directory -- not that it is the pinned image's filesystem. An inventory built from the wrong bytes would have been signed into three manifests. Checked instead: the inventory digest computed from the rootfs is sha256:29703c4d..., byte-identical to the one the shipped manifests already pin, so it is that image's. A caller who does not think to check gets no warning. THIS IS THE THIRD TIME TODAY, by three different actors, and none of them was the same one. The tooling refuses correctly every time and always AFTERWARDS: `repin check` runs in the pre-commit hook and asks whether a manifest pins the code it is measured by, which is a different question from whether the artifacts BESIDE the manifest still describe it. The second question is asked by nothing until `load_harness_catalog` fails for whoever pulls next. Recorded, not fixed -- new prevention is a maintainer's call, not a repair I was asked for. `catalog_source_revision` names the commit the registration was taken at and the pairing is recorded beside it. Tracked logs re-checked for host identity: 44 files, no hits. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…strain one more anchor Both were found by the read-only audit of the previous round, both confirmed by mutation, and both are the same defect: an inventory DERIVED FROM THE MECHANISM UNDER TEST shrinks exactly when that mechanism does, so deleting the thing the test exists to protect makes the test drive less and pass. CRITERION 35 was vouching for coverage that was not there. `test_harness_revision_monotonic` read the pinned-digest inventory out of `validate_harness_revision`'s OWN AST. Measured: delete the dataset, oracle, driver and container terms, leave only tolerance, and the derived set collapses from five fields to one, the test drives only what is left, and it PASSES. A sweep of 503 tests under that mutation gave a failure set identical to the baseline, and `grep 'cannot swap'` finds exactly one exerciser in the repository -- this test. A revision swapping the dataset, the oracle, the driver or the container out from under an already-locked Harness was refused by nothing any test noticed. The universe now comes from `LockedHarnessV1.model_fields`, which does not shrink when a comparison is deleted, and every pinned digest must be either compared or listed as deliberately uncompared with its reason. Deleting a comparison leaves that field unclassified and fails; adding one to the model fails until someone decides which side it is on. Re-mutated: the four-term deletion is now RED. A KNOWN GAP RECORDED RATHER THAN CLOSED. `result_schema_digest` is pinned on `LockedHarnessV1` and is NOT compared by the strengthening branch, so a revision can swap the schema its results are validated against. The schema can move without the driver moving -- that happened on this tree today. Closing it is a production change to `validate_harness_revision` and a maintainer's call, because it would also refuse a revision that legitimately follows a regenerated schema. It is now in the exclusion list with that reason attached instead of being invisible. CRITERION 49, both halves. The test selected trust anchors by NAME SUFFIX, so an anchor named for its ROLE was invisible: deleting `HarnessAttestationV1.execution_identity`'s `Field(pattern=...)` left the test green while the field accepted "" and "a"*12. And a second live instance of the same production defect the criterion is about: `KnowledgeSkillEntryV1.body_store_key` -- the key a Skill BODY is fetched by -- was a bare `str` accepting "", short values and uppercase, while all three producers supply a full content address and its sibling on the next line has carried the constraint all along. Constrained now. I WROTE THE EIGHTH INSTANCE WHILE FIXING THE SEVENTH, and caught it by mutation rather than by review. The first repair selected anchors by whether the field CARRIES the constraint -- which reads better and is worse, because deleting the constraint then removes the field from the inventory and the test goes green on exactly the defect it was rewritten to catch. Measured: that version passed with `execution_identity` unconstrained. The role-named anchors are pinned by name in an explicit classification instead, with a sibling test that fails if one is renamed or removed so the list cannot go stale silently. Both mutations are now RED. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three times today a manifest moved without its evidence being re-earned, by three different actors, and every one of those commits was clean. The pin gate asks whether a manifest pins the code it is measured by; nothing asked whether the artifacts BESIDE it still describe it. Moving a manifest passes the first and fails the second, and the failure surfaces later, in `load_harness_catalog`, in the working tree of whoever pulls next -- and it takes the whole catalog down rather than one row. IT ASKS THE LOADER. The obvious gate compares each manifest's `manifest_digest` against the back-references in the report and evidence beside it. That is three of the comparisons `load_harness_catalog` already makes -- it also checks each artifact's own digest, its harness id, the approval, and the digest the catalog row advertises -- so writing those three would be a subset standing in for a definition that exists, and would go quiet the day a fourth cross-check was added. The property wanted is "the catalog loads", so that is the question asked. 177 ms. IT IS A SEPARATE FILE. `repin_and_promote_harness` is held to naming no path inside the published harness tree, on the principle that it cannot write a bundle it cannot name, and a test scans its constants to enforce that. This check must READ those bytes. Moving it in would turn that guard red rather than quietly relaxing it. IT HAS ITS OWN ESCAPE, and that is the point rather than tidiness. Moving an instrument is exactly what the pin gate refuses, so every actor that moves one sets ARI_SKIP_PIN_CHECK -- correctly, it is the documented flow. One commit in this history says so in as many words while being the commit that left two Harnesses pinning drivers that no longer existed. A single variable carrying both assertions would hand that habitual escape the catalog too, which is the case this gate exists for. Measured on real commits in a scratch worktree: a manifest moved without its evidence is refused; ARI_SKIP_PIN_CHECK=1 does not get past it; ARI_SKIP_CATALOG_CHECK=1 does; a commit touching nothing under the harness tree is not checked at all. Both halves mutation-checked -- nesting the block inside the pin guard, and letting the gate compare fields itself, each turn a test red.
…solation The last three Harnesses whose registration evidence declared network_isolation from the REQUEST now derive it from a record. Each bundle ships six observations taken inside the pinned container by the isolated host itself: network_isolation: True network_probe: ENETUNREACH filesystem_isolation: True mechanism: landlock landlock_abi: 6 Four container executions per family, 15/15 gates each, clean=pass and negative=fail, signed over a source pin taken from a clean worktree at the commit whose bytes were measured. WHAT THIS FINISHES. test_no_shipped_bundle_claims_more_than_it_observed skipped all five bundles when it was written, then three, and now none: every row asserts against a run that recorded its own namespace. The claim and the record are the same object for the first time. ALL THREE IN ONE RUN, and that is not a convenience. The families share their executions and one license inventory, so re-registering one lets its bytes land under the other two signatures -- the surface refuses exactly that, and the inventory is only replaced when re_registering equals the whole registered set. Four attempts of mine were refused before I read that: an unextracted rootfs, a partial one missing the five non-dpkg licence paths, a dirty tree, and one harness at a time. THE ROOTFS IS DELIBERATELY PARTIAL, and worth saying so. Extracting the whole image stalled at 1.4 GB of 1.47 GB and consumed a two-hour allocation, which is the unsquashfs behaviour this repository already documents and which -p 1 did not avoid here. The licence inventory reads var/lib/dpkg/status, usr/share/doc, and five named files; extracting exactly those is 20 MB and seconds, and yields the same inventory because nothing else is read. Container identity is not established from it -- that is the SIF's byte digest against its site binding. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Six items were declared MOVED from one plan to another and were in none
of the receiving plans, so each existed nowhere while both plans read as
though it were owned. Verified absent by grep before acting; each is now
recorded where the declaring plan said it went, and the declaring plan
repointed at that landing.
Three are open questions with no answer anywhere, recorded honestly as
open so deleting a plan cannot lose them:
03 -> 05 sub-run governance / ARI_DISABLED_TOOLS_FOR_CHILD (also 00's
Q-15, which routed through 03). The stub's inert behaviour
was never the open part -- that is already permanent doc in
three languages; the open part is whether sub-run spawning
is governed at all.
05 -> 01 the _run_loop refactor, absent from 01's R1-R8, now R9. The
plans sized that function at ~925 lines; it is ~1,630 today.
15 -> 05/07 the exploration reviewer binding. reviewer is a founded
evolvable prompt role with no component identity, so
exploration-side leniency is unaccusable; the decision splits
across 05 (who may be implicated) and 07 (founding a
component to receive the binding).
One was already permanent and is repointed rather than duplicated:
15 -> 10 R5 UtilityRecord. rqgm_schemas.md already states the finding
more completely than R5 did, so 10 records the arrival and
points at it.
Two needed a permanent home rather than another plan:
12 per-call epoch attribution was deferred to nobody and its
"(documented)" parenthetical was false. It is true now:
troubleshooting.md gains the limitation in en/ja/zh. Reading the
code to write it showed the risk's mechanism was also wrong -- skill
calls are not best-effort attributed, they carry no epoch at all,
which contradicts the plan's own 5.4. Noted, not amended; that one
is the maintainer's.
00 Q-51's final call was owed at Task 13 wrap-up and 13 said nothing.
Half is answered by publication (env vars freeze by rule); half is
not (RQGM checkpoint files are documented but absent from
release_policy.md's enumeration). Recorded as the split it is.
No completion, deletion or delete-after criteria touched; no status table
touched; no plan deleted.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzZuTFFv37eeHja2NY4kqr
Three plan files were the only copy of a design decision the permanent docs claimed to carry, so a reader had to open a task plan -- or the source -- to learn what a rule id meant. - The shipped T1-T21 transition table now sits in the schema reference, one row per rule id with its triggering input, its edge-specific guards, the three universal guards, the T16 (from, to) encoding decision and the forbidden-complement rule. The reference used to name the table and point at transition_rules.py; T7, T12 and T17 appeared in no table row anywhere. - The M1-M10 meta-tier authority matrix now sits in the architecture page, each MAY-NOT row against the enforcement point that ships rather than against a convention, plus the MAY list it is the complement of. Invariant 8 paraphrased four rows and no page carried the other six. - The governed-rewrite vs ungoverned-smuggling distinction now sits under the "weights are rewritten at every boundary" claim that creates the apparent contradiction. It survived only in MetricSpecWeightCap's docstring, which its own plan says is not enough. All three in en/ja/zh with matching heading structure. The plans keep their text and gain a dated note pointing at the permanent home; no completion criterion, deletion criterion, checklist or status table is touched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzZuTFFv37eeHja2NY4kqr
…ontent
The ari_rqgm_paper plans were the normative reader of fourteen ari_rqgm
plans: their bodies deferred BY SECTION for design content ("snapshot layers
per ../ari_rqgm/07 §5.2", "validate_capability (../ari_rqgm/04 §5.4 item 3)",
"the score-comparability invariant from ../ari_rqgm/10 §5.6"). Each of those
sections has since been migrated to a permanent page, so the citation now
names that page instead — 72 citation sites, 69 links plus 6 bare section
references, each checked by reading what the cited section actually says and
confirming the permanent page says it too:
../ari_rqgm/04 §5.4 items 3/5/11 -> reference/rqgm_schemas.md
(CK-ACC-*, CK-REG-00x, CK-CTX-001)
../ari_rqgm/04 fixed-layer rule -> guides/execution_modes.md
(the claim gate is never an evolution
target), key invariant 9
../ari_rqgm/07 §5.2/§5.3/§5.5 -> rqgm_prompt_spec.schema.json, the
runtime walkthrough's six-stage ladder,
the four facades
../ari_rqgm/10 §5.1/§5.3-5.6/§6 -> key invariant 6, frontier-repair
schemas, and the state page's
stale/invalidated/removed vocabulary
../ari_rqgm/13 §3/§5.2/§5.3/§5.4 -> guides/rqgm_evaluation.md
../ari_rqgm/15 §5.3/§5.6 -> "The accountability binding on
validated_attack"
../ari_rqgm/12 §5.3/§5.7 -> configuration's one-schema-home caps,
internal_boundaries' context views
../ari_rqgm/01 §7, /02 §5.6, /05
§5.3, /06 §5.4/§5.8, /08, /09 -> the RQGM mode boundary, the epoch
freeze, the motion-pipeline records,
key invariants 4 and 7, the four facades
/08 now has no reference of any kind from this set, and /01, /02, /05 and /09
none either; /04's only remaining mentions are the two Depends-on status
lines.
Left alone deliberately: every ORDERING dependency (the INDEX Depends-on
column, each plan's Status line, "owned by parent 14", "parent 15 has
landed"), and every completion criterion, deletion criterion and delete-after
checklist — which is why three content citations survive inside criteria
(04 §11 -> /10 §5.4, 05 §11 -> /07, 07 §13 -> /15). Three more have no
permanent home and are reported to the maintainer rather than repointed to
the nearest plausible page: the Q-49 open-question register (../ari_rqgm/00
§5.9, cited three times), the replay-pool analogy quoted verbatim from
../ari_rqgm/06 §5.8, and the parent-set Task-12 test list (../ari_rqgm/12 §9).
check_doc_links.py: 0 broken links, 0 broken anchors; all 36 distinct
anchored targets also resolve against committed HEAD.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzZuTFFv37eeHja2NY4kqr
…overstating its source The citation-repointing pass produced exactly the failure it was warned against and its own audit caught it: a citation repointed at a page that does not carry the content reads as migrated and is not, so the next reader stops looking. Four sites, each verified by reading the target rather than by matching the name. "NEVER KERNEL-WRAPPED" ATTRIBUTED TO A PAGE THAT DOES NOT SAY IT, twice. docs/guides/execution_modes.md has zero occurrences of the phrase; the claim is made at docs/reference/rqgm_schemas.md and docs/concepts/rqgm_architecture.md. Both sites now cite the register that states it about the claim gate. The Layer-0 half of each sentence still cites execution_modes, which does carry it. A COUNT THE TARGET DOES NOT SUPPORT. paper/05 said "the four prompt-snapshot layers" and cited `architecture.md#test-ci-and-docs-surfaces`. That section is the right home -- it describes the prompt-snapshot layers -- but as a hand-maintained hash pin plus raw and rendered goldens, and its own "four" is a different four (the contract-snapshot surfaces, three as first written plus the viz REST inventory). The count came from the plan and is not carried anywhere, so it is dropped rather than pointed at a page that appears to support it. A CITATION NAMING THE RIGHT TARGET AND LINKING TO ANOTHER. paper/05 said "the fixed transition table's topology-agnostic inherited coverage" and linked to the four facades plus a config section -- while the transition table had just been given a permanent home in the same batch. Repointed at it. M3 OVERSTATED ITS SOURCE, in all three languages. The row said `DEFAULT_FORBIDDEN_TARGETS` "names it explicitly" of four things; measured, it names `fixed_verifier` and `constitutional_kernel` and not the metric recomputer or the claim-evidence gate, which are excluded by the allowed-targets rule instead. The row now says which mechanism does which, because a reader checking the cell against the constant would otherwise find it wrong and have no way to tell whether the rule or the record was. The anchor I first wrote for the register was itself wrong -- the heading's ellipsis collapses to a single hyphen, not two -- and the doc-link checker caught it. Gates now: 0 broken links, 0 broken anchors, doc-sources 0 errors. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`readme_sync --check` was red at HEAD -- a hard gate with no continue-on-error, so no PR from this branch could pass -- because `check_catalog_loads.py` and `test_catalog_load_gate.py` landed without their Contents entries. Written out rather than left as the placeholder, because the thing worth recording is WHY they are separate from the pin gate: "does this manifest pin the code it is measured by" is repaired by re-pinning, and one surface both asks and repairs it; "do the artifacts BESIDE this manifest still describe it" is repaired only by re-earning them, and no amount of re-pinning helps. Also why the check ASKS `load_harness_catalog` instead of comparing three back-references itself, why it is a separate FILE from the re-pin surface, and why its escape is `ARI_SKIP_CATALOG_CHECK` and deliberately not the pin gate's -- every actor that moves an instrument already reaches for that one, so a single variable would have handed the habitual escape the case this gate exists for. Seven `— TODO` entries remain in ari-core/tests/README.md, none of them mine and none of them gating: the gate compares Contents path structure and never reads a description. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…tly give Both amended by the maintainer, on questions raised by the migration that carried their content into the permanent docs. Recording who decided and why, because a criterion that changes without a reason is indistinguishable from one bent to make itself met. PLAN 09 asked for the transition table "reproduced verbatim". Its §5.2 is 19 rows of planning prose with guard names the code no longer uses; the shipped `TRANSITION_TABLE` is 21 rows. Verbatim would have put a stale table in the permanent reference under a criterion reading as satisfied -- the exact failure this procedure exists to prevent, arriving through the procedure. The criterion now asks for the shipped table with each row's decision and its reason, which is what was written. PLAN 14 named "the permanent RQGM developer guide" as the destination. No document carries that name; docs/guides holds rqgm_migration, rqgm_evaluation and rqgm_gui, none of which is where the contradiction arises. The criterion now names the architecture page, which is where it arises -- the §5.9 paragraph sits directly under the claim that weights are rewritten at every boundary. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
WHAT THIS CHANGES: nothing. `git diff --cached HEAD` is empty. The merge exists so PR #81 can build a merge ref, because nine of the ten workflows fire on `pull_request` to main and GitHub runs none of them while a PR is CONFLICTING -- which is why "CI green", a criterion under all 55 files in docs/plans, had never been evaluated on this branch at all. WHY IT IS EMPTY, measured rather than assumed. Of main's 279 non-dependabot commits since the 2026-05-29 merge base, 278 already exist in this branch's history under different hashes -- this branch is main's work rebased, plus 762 commits on top. The one exception, "fix 071 ledger hash", edits docs/refactoring/reports/orchestration_status.md, a file main itself deleted at 087f299 and which exists on neither side. Dependencies are ahead here, not behind: react ^19.2.8 against main's ^18.3.1, plus @tanstack/react-query and pdfjs-dist that main does not carry. So all 396 conflicts were the same content arriving twice, and every one resolved to ours. THE EIGHT FILES MAIN WOULD HAVE RESTORED, and the reason they are not here. Git offered eight paths present on main and absent here, and each was DELETED BY THIS BRANCH in a named commit: the evaluator prompt trio at 9d1817a "make scientific evaluation fail closed", ari-skill-hpc's server.py and slurm.py at 19ddaf2 "expose public HPC runtime package", two paper prompts at 50f255c "make paper builds evidence locked", and a replicate snapshot at 4dc05f0. Taking them would have resurrected deliberate deletions -- the same trap that makes merging origin/RQGM wrong, where 17 of its 25 unique files are the gui_refresh plans this campaign migrated and deleted. Each was checked against its deleting commit rather than by inspection. ANNOUNCED FIRST. Three live peer sessions were asked before this started; all three cleared it, and two measured their own exposure independently. One warned that 30 files inside the driver digests live under ari-core/ari and that moving any of them stales all five Harness manifests at once -- correct in principle, and it does not apply: main changed ZERO of the 27 digest-covered files since the merge base, so the merge cannot move a digest. Confirmed after resolving: "every manifest pins the code it is measured by" and "the shipped catalog loads". Gates before committing: READMEs in sync, 0 broken links and 0 broken anchors, doc-sources 0 errors, public-API 0 breaks. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
kotama7
pushed a commit
that referenced
this pull request
Aug 23, 2026
WHAT THIS CHANGES: nothing. `git diff --cached HEAD` is empty. The merge exists so PR #81 can build a merge ref, because nine of the ten workflows fire on `pull_request` to main and GitHub runs none of them while a PR is CONFLICTING -- which is why "CI green", a criterion under all 55 files in docs/plans, had never been evaluated on this branch at all. WHY IT IS EMPTY, measured rather than assumed. Of main's 279 non-dependabot commits since the 2026-05-29 merge base, 278 already exist in this branch's history under different hashes -- this branch is main's work rebased, plus 762 commits on top. The one exception, "fix 071 ledger hash", edits docs/refactoring/reports/orchestration_status.md, a file main itself deleted at 087f299 and which exists on neither side. Dependencies are ahead here, not behind: react ^19.2.8 against main's ^18.3.1, plus @tanstack/react-query and pdfjs-dist that main does not carry. So all 396 conflicts were the same content arriving twice, and every one resolved to ours. THE EIGHT FILES MAIN WOULD HAVE RESTORED, and the reason they are not here. Git offered eight paths present on main and absent here, and each was DELETED BY THIS BRANCH in a named commit: the evaluator prompt trio at 9d1817a "make scientific evaluation fail closed", ari-skill-hpc's server.py and slurm.py at 19ddaf2 "expose public HPC runtime package", two paper prompts at 50f255c "make paper builds evidence locked", and a replicate snapshot at 4dc05f0. Taking them would have resurrected deliberate deletions -- the same trap that makes merging origin/RQGM wrong, where 17 of its 25 unique files are the gui_refresh plans this campaign migrated and deleted. Each was checked against its deleting commit rather than by inspection. ANNOUNCED FIRST. Three live peer sessions were asked before this started; all three cleared it, and two measured their own exposure independently. One warned that 30 files inside the driver digests live under ari-core/ari and that moving any of them stales all five Harness manifests at once -- correct in principle, and it does not apply: main changed ZERO of the 27 digest-covered files since the merge base, so the merge cannot move a digest. Confirmed after resolving: "every manifest pins the code it is measured by" and "the shipped catalog loads". Gates before committing: READMEs in sync, 0 broken links and 0 broken anchors, doc-sources 0 errors, public-API 0 breaks. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Quality Report
Checkers
Areas
Dead code
|
CI's `mcp-tool-contracts` job caught this on the first run this branch has ever
had: `sync_skill_metadata.py` reported eight shipped JSON Schemas out of date
against the models they are generated from. The generated artifacts are derived,
the models are the source, and nothing local had compared them.
At least one is mine. Constraining `KnowledgeSkillEntryV1.body_store_key` and
`HarnessAttestationV1.execution_identity` to `SHA256_DIGEST_PATTERN` earlier
today added `"pattern": "^sha256:[0-9a-f]{64}$"` to the published schemas, and
the published copies still described the unconstrained fields. This is the same
shape a peer session hit this morning from the other direction -- a model field
removed while its generated schema kept declaring it required -- so the drift
runs both ways and the generator is the only thing that closes it.
COMMITTED WITH ARI_SKIP_PIN_CHECK=1, and disclosed because that escape is
routinely reached for and should never be silent. Regenerating a result schema
moves `expected_result_schema_digest`, and three manifests --
hpc_gemm_correctness, hpc_spmm_correctness, hpc_stencil_correctness -- now pin a
digest the code no longer has. The pin gate refused correctly.
The re-pin and re-earn follow in the next change, from a CLEAN tree, and that
order is the point: a derived pin taken over uncommitted bytes names a commit
whose contents no checkout can reproduce, which is a defect shipped in this
repository this morning and caught only by a promote from a clean checkout.
The catalog still loads; this staleness stops `prepare` at run time rather than
breaking the load.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e catalog Regenerating the eight drifted schemas moved `expected_result_schema_digest`, which staled hpc/gemm-correctness, hpc/spmm-correctness and hpc/stencil- correctness. Re-earned through the signed re-registration, four controls each: all three clean=pass negative=fail runs=4 gates=15/15. Taken from a CLEAN tree at the schema commit, which is the point of splitting these two changes: a derived pin computed over uncommitted bytes names a commit whose contents no checkout can reproduce. `catalog_source_revision` names the commit the registration was taken at, and the pairing is recorded beside it. That pin was also red in CI for a second reason, and it was the guard working: the catalog had moved to `aff7dee4` under a revision still reading `e8a99f7e`, so a run pinned to that label could not say which of two catalogs judged it. The pairing now names one catalog. Both harness checks after: "every manifest pins the code it is measured by" and "the shipped catalog loads". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CI's `mcp-tool-contracts` job, second sub-check: nine source pins across four
Provider packages named commits and package digests the tree no longer has --
`ari-skill-coding`, `ari-skill-hpc`, `ari-skill-tool-registry` and
`ari-skill-web`, each pinning a `full_commit_sha` from an earlier state of this
branch. Not caused by anything in this change; the pins were simply never
retaken as the branch moved, and nothing local compares them.
That gap is the reason the gate exists and its own README says so: the loader
checks only `manifest_sha256`, so a package edit that leaves the manifest alone
drifts in silence, while a manifest edit fails the whole load. The commit and
package digests mean something only because this hard gate compares them.
Re-pinned with `--update`; verify mode now reports "provider catalog pins match
the tree". Blast radius checked rather than assumed: all six Provider capability
pins still match the ontology, both harness checks still pass ("every manifest
pins the code it is measured by", "the shipped catalog loads"), and the rest of
the job passes locally -- skill metadata up to date, skill manifest conformance
passed.
One pre-existing note surfaced by the capability check and left alone: an
`ari-cuda-environment-validator` bundle pins an earlier contract and is
superseded by a sibling bundle of the same Provider, so there is nothing to do
unless that substrate returns.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
kotama7
force-pushed
the
bfts_compare_plans
branch
from
September 14, 2026 16:49
3076514 to
8fc0ce2
Compare
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.
Draft, opened to run CI. Not requesting merge.
Why
docs/planscan only be deleted once each plan's own criteria are met, and one of those criteria — "CI green" — could not be evaluated: no workflow had ever run on the working branch. Nine of the ten workflows trigger onpull_requesttomain, so a PR is what runs them. This branch exists for that.The branch is pushed here rather than to the fork it tracks because that fork has no
mainbranch and its workflows therefore cannot fire.What is in it
Known risk
dashboard-frontend.ymlhas never run. It was added on this branch and there is no node toolchain on the machine this was developed on, sonpm ci/typecheck/testare unverified. If anything here is red, that is the first place to look.Everything else was run locally: full suite 6660 passed / 0 failed,
readme_sync --checkin sync, 0 broken links and 0 broken anchors, doc-sources 0 errors, public-API contracts 0 breaks, prompt snapshots 175 passed.