Skip to content

OutputContractRef meaning fork: opaque identity + sealed obligation resolution - #10713

Merged
briansrls merged 17 commits into
mainfrom
session/snappy-lark-51
Sep 7, 2026
Merged

briansrls merged 17 commits into
mainfrom
session/snappy-lark-51

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Defect: product.fabric.work OutputContractRef carried two meanings in one brand — opaque contract names and content-serialised obligation payloads. Confirmed with warm-moth-142: content-serialised was anemic modeling (String leaf hiding named parts), not an alternate naming convention.
  • Surviving meaning: opaque OutputContractRef. Obligations → DeclaredOutputObligations on WorkContract. resolve_output_obligations → OutputObligationsResolution (Resolved | Unreadable); ResolvedOutputObligations is sole_constructor on the source→.dag path.
  • Revision brand: OutputObligationsRevision is branded NonEmptyStr (WorkKey shape). A bare ContentHash alias and ContentHash where brand both fail — the former is a nickname; the latter cannot cast a sum variant.
  • Judgment in the value: OutputObligationsJudgment (ObligationsJudgedAtJobStart | ObligationsJudgedAtAdmissionGate) required at resolve and stamped on the sealed result.
  • Work binding: resolve takes requirements and refuses WorkKeyDoesNotMatchContract when the supplied key is not derive_work_key for that contract — Unreadable is a produced arm, not a decoration.
  • Rung honesty (path-scoped): structurally impossible on source→.dag (fixture RED). Emitted Rust mirrors sole_constructor as a public struct — outside this guarantee. Degradation: first Rust seed consumer against this carrier.
  • Consumption frontier (§3c): sealed resolution family is not yet read by a production gate in this closure. Named consumer: durable-commit admit_job_publication (warm-moth-142 / fabric-M0 F0: the durable-completion authority, before the cache #10641). Trigger: that gate takes OutputObligationsResolution instead of a caller-supplied coproduct. Live production consumer of the roster half today: DeclaredOutputObligations in work_identity_material.
  • Cut: delete-first — content-serialisation removed from required_build_contract_from_materials. Unblocks fabric-M0 (fabric-M0 F0: the durable-completion authority, before the cache #10641 / warm-moth-142).

Producer census by shape (before the cut)

Instrument: every WorkContract { … output_contract: … } construction under dag/ whose field inhabits OutputContractRef. Verified the instrument can find content-serialised form by matching the historical spelling gunbc.required-witnesses-build.outputs: + framed_string — nonempty before the cut, 0 after.

Shape Count Sites (by symbol)
content-serialised 1 gunbc.fabric_witness_run required_build_contract_from_materials — deleted
opaque name 8 production: floor_work_contract (1); fixtures: fabric_grant_issuance_witness (2), fabric_terminal_contract_witness (3), fabric_capacity_class_witness cc_contract (1); product.training.resolution training_work_contract (1) — content-addressed digest as opaque name (derived from content, no decodable payload; not a third contract)

Strongest census line: parse consumers of the content-serialised encoding: 0. The framed form was write-only — produced by one site and decoded by nobody. Cheapest fork to cut; no live reader could have mis-deserialised the other shape because nothing deserialised. The harm was silent identity salt / missing roster authority.

Consumers of WorkContract.output_contract after the cut: work_identity_material (opaque string bytes into the work key); resolve_output_obligations (opaque identity + structured obligations, sealed).

Outside this diff still constructing the old shape: 0 (residual grep of the historical spelling; pattern verified to match before reporting zero).

Roster presence is construction, not a readable/unreadable coproduct

output_obligations is a required field of WorkContract. Holding a contract therefore holding a roster: "the declaration could not be read" has no producer downstream of that record. OutputObligationsUnreadable is only a caller error (WorkKeyDoesNotMatchContract), not an unreadable declaration.

Consequence for fabric-M0 (admit_job_publication / #10641): ArtifactObligationsUnreadable / PublishObligationsUnreadable become uninhabitable against this carrier — a permanently unreachable arm, which DESIGN §4b treats as worse than absent if cited as coverage. Warm-moth-142 will delete that arm or re-home it onto WorkKeyDoesNotMatchContract when wiring, rather than leaving a safety state that can no longer fire. This is a climb (mitigated coproduct → unwritable absence), not a dropped refusal.

Gap recorded, not owned here

Attempt↔work binding so a gate can refuse a substituted sealed resolution for a foreign work is warm-moth-142's to close (WorkClaim exists; a reified (attempt, WorkKey) check at admit_job_publication does not). Not stacked on this PR. Work-key mismatch at resolve is the carrier-side half of that binding.

Inherited floor red (not this cut)

Required-witnesses-floor currently fails on main's declarations phase, introduced by #10706 OutsideModeledGuarantee stamps that deliberately cite absent capability decls. The four names:

  • v2.lens.grounding confirm_judge_should_ground
  • v2.lens.enforcement.complexity_contract_subject unrestricted_semantic_complexity_equivalence_procedure
  • v2.lens.synthesis unrestricted_cheaper_equivalent
  • v2.lens.cost capability_absent_from_decl_facts (planted in outside_modeled_guarantee_witness_test)

This PR does not exempt or repair that gate. On floor run 34085335324 (this cut merged into then-main), those seven CITED-DECLARATION-ABSENT findings were the only declarations-phase reds; all nine test.claim.fabric_output_contract_resolution_witness claims were planned-and-passed on that same run. When main is repaired, merge it (do not rebase away this evidence).

Test plan

  • claim_batch resolution witnesses — empty Resolved, foreign-key Unreadable, judgment stamp, forged SoleConstructorViolation RED
  • required-build possession + output-identity PASS after the cut
  • CI required lanes: blocked on inherited OutsideModeledGuarantee stamps and stall carriers (follow-up) #10706 declarations red (named above); this cut does not widen that gate

@gunbai-bot
gunbai-bot Bot force-pushed the session/snappy-lark-51 branch from 01c9754 to 7769bac Compare September 7, 2026 03:07
@gunbai-bot

gunbai-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

review 61625 (on 01c9754) asked for two things that are now on HEAD f503017:

  1. Unreadable producer. resolve_output_obligations no longer always returns Resolved. A work_key that is not derive_work_key for the contract+requirements mints OutputObligationsUnreadable { cause: WorkKeyDoesNotMatchContract {} }. Discriminating witness: foreign_work_key_is_unreadable_not_resolved. Empty still resolves as Resolved, not Unreadable.

  2. §3c consumer. Production gate is not in this closure. Named frontier on ResolvedOutputObligations: durable-commit admit_job_publication (warm-moth-142 / fabric-M0 F0: the durable-completion authority, before the cache #10641). Trigger: that gate takes OutputObligationsResolution instead of a caller-supplied coproduct. Live roster consumer today is DeclaredOutputObligations in work_identity_material.

review 61662's brand request is also on this head: OutputObligationsRevision is branded NonEmptyStr (WorkKey shape), minted via serialize_content_hash.

— sent from snappy-lark-51

@gunbai-bot

gunbai-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

review 61637 (on 7769bac) repeats review 61625. Both are already on HEAD 41c4140:

  1. Unreadable has a producer. resolve_output_obligations refuses a work_key that is not derive_work_key for the contract+requirements as OutputObligationsUnreadable { cause: WorkKeyDoesNotMatchContract {} }. Discriminating witness: foreign_work_key_is_unreadable_not_resolved. Empty still resolves as Resolved.

  2. §3c consumer is a declared frontier on ResolvedOutputObligations: durable-commit admit_job_publication (warm-moth-142 / fabric-M0 F0: the durable-completion authority, before the cache #10641). Trigger: that gate takes OutputObligationsResolution instead of a caller-supplied coproduct. Live roster consumer in this closure: DeclaredOutputObligations in work_identity_material.

— sent from snappy-lark-51

@gunbai-bot

gunbai-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

review 61662 (on 17b8ea7) asked to brand OutputObligationsRevision so a foreign digest is ill-typed.

Landed: type OutputObligationsRevision = NonEmptyStr where brand("OutputObligationsRevision"), minted via serialize_content_hash(content_hash_of_value(...)) — same identity shape as WorkKey.

Not ContentHash where brand(...): ContentHash is a sum, and the floor refused cannot cast Variant to OutputObligationsRevision on that spelling. Bare = ContentHash was the nickname the review named. Branded serialized digest keeps computation identity without admitting an unbranded ContentHash into the sealed field.

— sent from snappy-lark-51

@gunbai-bot

gunbai-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

review 61719:

  1. WorkKey collision from flattening output_manifest + terminal_result_manifest — agreed, that was a discrimination regression vs the old framed groups. Fixed on HEAD: one roster of typed OutputObligation { id, kind } (OutputArtifactObligation | TerminalResultObligation), identity material includes kind, required-build uses declared_output_obligations_from_manifests. Witness artifact_versus_terminal_kind_is_work_key_identity. Resolution still exposes ids (warm-moth: one roster, not two).

  2. SubstrateInputsOnly vs compile_dag_diagnostic_census — not relabeling to ReadsLiveTree. gunbc.guarantee_probe_corpus adjudicates that census walks the live checkout, and says do not repair by retyping: ReadsLiveTree is declined (DeclinedLiveTree) before the fold, which would take the forged SoleConstructor RED off the required floor. SubstrateInputsOnly while calling census is the same mis-declaration as match_exhaustiveness_coproduct_witness / direct_call_argument_type_witness, and is currently why any census probe executes. Relabeling would fabricate affected-set eligibility and drop the discriminating RED. Owner of DeclinedLiveTree / that note, not this cut.

— sent from snappy-lark-51

@gunbai-bot

gunbai-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

Addressed review 61733.

Deleted declared_output_obligations(ids:) so kind cannot default to artifact. Callers now name the coproduct: declared_artifact_obligations, declared_terminal_obligations, or declared_output_obligations_from_manifests. Floor summary and outputs-verdict are terminal obligations. Training keeps the digest as opaque output_contract and owes the stable subject training-low-rank-adapter.

— sent from snappy-lark-51

@gunbai-bot

gunbai-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

Addressed review 61784.

ResolvedOutputObligations.required is now List<OutputObligation> (id and kind), copied from the declaration at resolve. Witness same_id_artifact_and_terminal_remain_distinct_after_resolve requires artifact "a" + terminal "a" to stay unequal to two artifact "a"s after sealing.

— sent from snappy-lark-51

@gunbai-bot

gunbai-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

Addressed review 61792 (advisory): added resolved_roster_findings, citation_field_suffix, next_rung_trigger_citation_findings, next_rung_trigger_citation_findings_against, and a_next_rung_trigger_that_resolves_is_the_stamp_firing_not_a_lost_control to gunbc.declaration_index_seed_growth hand_authored_declarations. Trigger count 62→67.

— sent from snappy-lark-51

@gunbai-bot

gunbai-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

Addressed review 61802.

NEXT_RUNG_TRIGGER_CITATIONS is now on gunbc.declaration_index_seed_growth hand_authored_declarations, beside PRE_EXISTING_CITATION_DEBT. Dissolution trigger census 67→68, matching the list.

— sent from snappy-lark-51

gunbc-ci-auto-heal and others added 17 commits September 7, 2026 09:26
…sealed roster

OutputContractRef held both plain names and content-serialised obligation
payloads, so no consumer could tell which it held. Keep the opaque name,
put DeclaredOutputObligations on WorkContract, and mint terminal-success
rosters only through resolve_output_obligations (sole_constructor RED).

Co-authored-by: Cursor <cursoragent@cursor.com>
…le_constructor rung

Warm-moth-142: revision identity alone does not answer start-vs-gate; the
sealed result now carries OutputObligationsJudgment. Also correct the
unwritable claim to path-scoped rung 4 on source→.dag with a named
degradation when a Rust seed consumer appears.

Co-authored-by: Cursor <cursoragent@cursor.com>
Body and field-inline // comments refuse under the annotation channel;
CI floor failed on WorkContract and required_build_contract_from_materials.

Co-authored-by: Cursor <cursoragent@cursor.com>
resolve_output_obligations now takes requirements and refuses a foreign
work_key (WorkKeyDoesNotMatchContract). Declared frontier: warm-moth-142
admit_job_publication (#10641). Reclassify content-addressed digests as opaque.

Co-authored-by: Cursor <cursoragent@cursor.com>
A bare `= WorkKeyDoesNotMatchContract` parsed as a type alias, so resolve
and heal both refused unresolved type / undefined variable.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Bare ContentHash alias let any digest inhabit the sealed revision field;
brand matches every other identity carrier in work.dag (§3 / §6).

Co-authored-by: Cursor <cursoragent@cursor.com>
ContentHash is a sum; casting a variant into ContentHash-where-brand refused
at runtime. Same identity shape as WorkKey: serialize then brand.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
serialize_content_hash is family-asymmetric; this carrier never enters the
other arms, so revision identity is not riding the incidental width split.

Co-authored-by: Cursor <cursoragent@cursor.com>
Concatenating required-build manifests made split and collapsed id lists
the same WorkKey. Kind is identity material; resolution still returns ids.

Co-authored-by: Cursor <cursoragent@cursor.com>
An ids-only constructor silently stamped OutputArtifactObligation, so terminal
subjects (floor summary, outputs-verdict) minted the wrong work key. Training
now owes a stable adapter id rather than reusing the contract digest.

Co-authored-by: Cursor <cursoragent@cursor.com>
Declarations was failing the floor on three stamp required_capability refs
and one fixture absence. Those names must stay unresolved; PLANTED_CONTROL
is the wrong roster because resolve there means a lost control. Same join as

Co-authored-by: Cursor <cursoragent@cursor.com>
The work key already treated artifact vs terminal as distinct owed subjects;
dropping kind at resolve made same-id mixed rosters collapse for the gate.

Co-authored-by: Cursor <cursoragent@cursor.com>
…-growth roster.

The four production fns and the discriminating test landed in the same boundary the
justification already lists at item grain; leaving them off the roster was a silent delta.

Co-authored-by: Cursor <cursoragent@cursor.com>
…th roster.

The join helpers were listed; the production roster they close over was not.
PRE_EXISTING_CITATION_DEBT is already a DeclarationRef on the same justification.

Co-authored-by: Cursor <cursoragent@cursor.com>
PLANTED_CONTROL stays empty; #10706 stamp sites remain on NEXT_RUNG_TRIGGER_CITATIONS.

Co-authored-by: Cursor <cursoragent@cursor.com>
@gunbai-bot
gunbai-bot Bot force-pushed the session/snappy-lark-51 branch from 74867ca to 19ab64b Compare September 7, 2026 09:31
@briansrls
briansrls merged commit 81d5f24 into main Sep 7, 2026
6 of 8 checks passed
@briansrls
briansrls deleted the session/snappy-lark-51 branch September 7, 2026 15:30
@briansrls
briansrls restored the session/snappy-lark-51 branch September 7, 2026 15:36
@gunbai-bot
gunbai-bot Bot deleted the session/snappy-lark-51 branch September 7, 2026 16:13
@briansrls
briansrls restored the session/snappy-lark-51 branch September 7, 2026 16:28
@gunbai-bot
gunbai-bot Bot deleted the session/snappy-lark-51 branch September 7, 2026 22:38
gunbai-bot Bot pushed a commit that referenced this pull request Sep 7, 2026
The body already walks the checkout; SubstrateInputsOnly was the lie. Same finding on the two gated probes left behind last round, plus the #10713 fabric specimen. Census and the fourth-face row stay; this does not retire the class.

Co-authored-by: Cursor <cursoragent@cursor.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 8, 2026
The body already walks the checkout; SubstrateInputsOnly was the lie. Same finding on the two gated probes left behind last round, plus the #10713 fabric specimen. Census and the fourth-face row stay; this does not retire the class.

Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls pushed a commit that referenced this pull request Sep 8, 2026
* Declare the declared-type census probes ReadsLiveTree now that DeclinedLiveTree is gone.

compile_dag_diagnostic_census walks the checkout; SubstrateInputsOnly was a dodge so the floor would fold them. They already match required_gate_prefixes, so the honest arm executes without a fourth fabricated stamp.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Revert "Declare the declared-type census probes ReadsLiveTree now that DeclinedLiveTree is gone."

This reverts commit 891a884.

* File the live-tree stamp as a fourth face of the missing digest join, and derive the disagreement set.

The stamp and the body are peers with no relating arm: parse_entry_live_tree_disposition never looks at the call. Do not restamp. Identity-join the named specimens through an unquoted-call census at entry grain.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Correct discovered census-probe stamps to ReadsLiveTree.

The body already walks the checkout; SubstrateInputsOnly was the lie. Same finding on the two gated probes left behind last round, plus the #10713 fabric specimen. Census and the fourth-face row stay; this does not retire the class.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Correct the stamp-join receipt: fifth face, unmeasured skip harm, no count oracle.

The withheld restamp is a batch of hand stamps, not a forbidden honest correction; the 52 unmatched ReadsLiveTree rows are this detector's blind spots, not a disagreement set; skip eligibility is not a named production drop.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Name the skip mechanism: census is absent from effect_reach's host-sink roster.

Adding the marker is cheaper in authoring and is not the next rung: the conjunction still loses the remaining in-memory census specimen, and effect_reach's own ceiling row forbids patching the substring roster. Skip harm is a skip-eligible lie with no measured miss on record.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Keep the live-callee spelling scan in tests: it is a detector, not a seed join.

Production skip still uses stamps plus effect_reach. Review 62223 was right that a fourth roster in cli_run would be a parallel authority; the substring scan stays fail-open evidence for named identity-joins, not a wall and not a BuiltinSignature fork.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Derive live-sink spellings from the builtin registry; state why the detector is textual.

The census inhabits the same seed reader as parse_entry_live_tree_disposition because entries may not resolve; callees_from_node needs a Node. The roster is no longer a pasted name list. Falsifier.yml is named as the deleted measuring cadence, not as a drop that happened.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Compare derived sink names as String, not &&str.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Say falsifier.yml's deletion removed the instrument that could have shown a skip-miss.

The previous sentence still admitted a reading that falsifier.yml itself dropped one of these identities.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Regenerate design-failure-modes.md from the merged failure-mode authorities.

The row already carries the falsifier wording; this is the derived projection of that authority plus main's new rows, not a hand splice.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Enumerate the live-tree stamp detector as SeedGrowthJustification.

Unenumerated hand src/v1 growth is a stop-line; the annotation beside the helpers is not that row.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Keep the live-tree spelling detector inside the test module.

Production skip never consulted it; a pub(crate) surface with only test callers was a dangling seed declaration. The mechanism test is named as lib-test diligence under rust_unit_tests_off_the_merge_path, not merge-path evidence.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Keep source_has_path_like_string_data private: the test already reaches it via super.

A pub(crate) widening had no extra caller and was unenumerated seed-surface growth.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Drop the single-element loop in the ignored detector corpus walk.

clippy: :single_element_loop failed required-witnesses-build on the one remaining named specimen.
Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant