Skip to content

(3D) PRINT-8: manufacturing manifest — seal the printer-asset join, refuse until a machine is registered - #10202

Merged
gunbai-bot[bot] merged 3 commits into
mainfrom
session/crisp-ibex-710
Sep 3, 2026
Merged

gunbai-bot[bot] merged 3 commits into
mainfrom
session/crisp-ibex-710

Conversation

@briansrls

@briansrls briansrls commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

First slice of PRINT-8: the manufacturing manifest binds a printed thing to the process that produced it.

This is the declared route of a live obligation, not a new idea. coupon_v1_open_obligations already carries PhysicalPrintInstanceAttributionUnsolved routed to AttributeByManufacturingManifestAndHandling. Two coupons off two printers are geometrically identical — the orientation datum makes one orientable, never attributable — so the binding cannot be recovered by inspecting the plastic and must be captured while the part is still on the bed.

No second identity for a printer

product.placement_supply.PhysicalAsset already carries instance identity, a catalog DeclarationRef naming the vendor product row, an optional physical serial and procurement provenance — and its charter already assigns vendor/product facts to extdeps and owned inventory to the product layer. A machine that produces parts rather than occupying a shelf is the same physical object with a role.

Minting PrinterNodeIdentity would have been two names for one unit — the net-concepts-by-re-invention failure of §2. I nearly did: the brief calls it "node-ness of the printers", and that name is what made a new concept look necessary. It was avoided by DFSing the concept DAG first, not by insight.

Why an admission exists at all

PhysicalAssetIdentity is a branded NonEmptyStr. A brand stops an arbitrary NonEmptyStr standing in for one; it does not make a duplicate or unregistered identity unwritable. So a consumer handed a bare identity has a string that looks authoritative and may name nothing.

The repair is deliberately not a stronger printer-only identity — that would put two identities on one machine and re-open what the section above closed. It is a sealed admission at the consuming boundary, the same shape as AdmittedRealizationV0: a value only a join against the authority can mint. A later corpus-wide migration of PhysicalAssetIdentity to an allocator-minted identity replaces this bounded wall without disturbing its consumers.

PrinterAssetAdmission has four arms rather than one refusal carrying a reason string, because a consumer cannot act on — and an operator holding the machine cannot be told — what a collapsed refusal means:

  • PrinterAssetAdmitted { binding }
  • PrinterAssetAbsent { requested }
  • PrinterAssetDuplicate { requested, matches } — the count, so the fold cannot silently take whichever row it reached first
  • PrinterCatalogMismatch { requested, expected_module, found_module } — a registered asset is not automatically a printer this program can qualify

The empty inventory is the point, not a gap

owned_printer_inventory is empty, and a witness asserts that the live roster therefore admits nothing. Until a serial is read off a machine, no coupon can be attributed to it. Pre-populating a plausible row would be a fabricated fact about hardware nobody has inspected, and every attribution built on it would inherit that. The tempting arm — admit an unregistered identity "for now" so a print can proceed — is the absorbing fallback, and it fails open exactly when the operator most needs the binding to be real.

Evidence

Six witnesses green by execution. The discrimination claim is verified by mutation, not asserted: replacing the identity join with a => true leaves the empty-inventory and single-row witnesses green and turns w_the_admitted_asset_is_the_one_requested_not_the_first_row red. That witness's annotation claims an implementation returning the first row regardless of the request would pass everything else and fail there — that claim is now executed.

w_the_expected_catalog_module_comes_from_the_manifest reads a1_mini_catalog_module rather than restating the path, so the witness cannot pass by testing a string it wrote itself. That is the exact defect PRINT-1 was reopened for.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TuCmz2HjuYzP6GWLgw11E4

… a machine is registered

The coupon authority already declared this binding unsolved -- coupon_v1_open_obligations
carries PhysicalPrintInstanceAttributionUnsolved routed to
AttributeByManufacturingManifestAndHandling -- so this is that declared route, not a new
idea. Two coupons off two printers are geometrically identical, so the binding cannot be
recovered by inspecting the plastic.

NO SECOND IDENTITY FOR A PRINTER. product.placement_supply.PhysicalAsset already carries
identity, a catalog DeclarationRef naming the vendor product row, an optional serial and
procurement provenance, and its charter already splits owned inventory from vendor facts.
A machine that produces parts is the same physical object with a role. Minting
PrinterNodeIdentity would have been two names for one unit -- the brief calls it
"node-ness of the printers", and that name is what made a new concept look necessary.

THE ADMISSION EXISTS BECAUSE THE CARRIER IS WEAKER THAN THE CONSUMER NEEDS.
PhysicalAssetIdentity is a branded NonEmptyStr; a brand does not make a duplicate or
unregistered identity unwritable. The repair is not a stronger printer-only identity --
that re-opens what the paragraph above closed -- but a sealed admission at the consuming
boundary, the same shape as AdmittedRealizationV0.

owned_printer_inventory is EMPTY and the live-inventory witness asserts that it therefore
admits nothing. That is the correct day-one state, not a gap: until a serial is read off a
machine, no coupon can be attributed to it. Pre-populating a plausible row would be a
fabricated fact about hardware nobody has inspected.

Six witnesses green by execution. The discrimination claim on
w_the_admitted_asset_is_the_one_requested_not_the_first_row was verified by MUTATION, not
asserted: replacing the identity join with `a => true` leaves the empty-inventory and
single-row witnesses green and turns that one red.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TuCmz2HjuYzP6GWLgw11E4
@gunbai-bot gunbai-bot Bot changed the title (3D) PRINT-N (3D) PRINT-8: manufacturing manifest — seal the printer-asset join, refuse until a machine is registered Sep 3, 2026
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review September 3, 2026 06:40
Brian Searls and others added 2 commits September 3, 2026 07:28
… the catalog citation, and the serial correction

Review 59176 (approve, non-blocking) raised two findings on the manufacturing manifest. Both were
real and both are addressed by evidence rather than by rewording.

THE SEAL HAD NO EVIDENCE NAMING IT. The manifest header bills AdmittedPrinterAsset as a value only a
join against the authority can mint. That is a rung claim, and nothing measured it -- the same shape
as the defect this program already hit once, where a sealed coproduct was asserted in a comment while
a foreign variant literal compiled clean. A three-witness census battery now forges the record from a
foreign module, pairs it with a lawful positive control over identical imports, and asserts the
differential, so the forged literal is the whole difference rather than a count dominated by the
shared closure.

THE CATALOG MODULE PATH WAS A LITERAL CHECKED AGAINST A COPY OF ITSELF. a1_mini_catalog_module was a
bare string and its witness compared it to the same string spelled again -- two authored copies
corroborating each other, which is not an oracle. It is now projected off a1_mini_catalog_ref, a
DeclarationRef naming a module and a declaration, which is the form v2.std.decl_ref_resolution can
resolve against the live tree. Deriving it instead from the extdeps module's own extdeps_model_scope
would be purer and is not available: 275 modules declare that name into one flat namespace, which
gunbc.design.reference_instrument already hit and answered with this same symbolic form.

WHAT IS STILL NOT CHECKED IS SAID OUT LOUD. No witness resolves that ref. declaration_ref_resolves
needs a decl_facts index -- an expensive whole-tree scan whose own evidence lives in test.claim.long
-- and it resolves against a POOL, so asserting it without first establishing that
extdeps.printing.bambu_lab_a1_mini is in this file's pool would risk a red meaning "wrong pool" while
reading as "citation broken". The citation is resolvable-in-principle and unresolved-in-evidence, and
the sibling file records that rather than leaving it as an apparent oversight.

A CORRECTION THE SIDE CHAT CAUGHT, ON THE DAY THE MACHINES ARRIVE. The roster annotation said it is
filled by reading the serial off each machine. PhysicalAsset.physical_serial is OPTIONAL, so a
printer present on the bench with an unread serial and a printer that has not arrived are different
facts; that wording would have reported a machine the operator is standing in front of as absent. A
row is allocated at receipt and durable individuation -- an operator-applied label suffices -- and the
serial CORROBORATES the binding rather than establishing it. The positive control already executes
this: every fixture row carries physical_serial: Absent, so an implementation that made a serial a
precondition reds there.

ALSO: a change detector removed. w_the_live_inventory_admits_nothing_today asserted the LIVE roster
is empty -- true today and false the moment a printer is registered, at which point someone edits the
witness to match, which is a test whose entire content is the manual update. It is replaced by two
permanent behavioural checks (an unregistered identity refuses; an identity missing from a POPULATED
roster refuses, which the empty case alone cannot establish) plus one live-roster property that
survives the roster growing. And the catalog comparison is lifted into asset_catalog_qualifies so the
witness consumes the manifest's rule instead of restating it.

THE LIVE-TREE BATTERY IS IN ITS OWN FILE ON PURPOSE. live_tree_disposition is a per-FILE declaration
and the required floor declines ReadsLiveTree witnesses, so folding these three in beside the eight
substrate-only ones would have silently taken all eight out of the required floor to buy three
non-gating ones.

AND THE CI RED THAT WAS MINE. required-witnesses-floor failed its DECLARATIONS phase:
CITED-MODULE-ABSENT on extdeps.printing.some_other_printer, a module path this file's foreign-catalog
fixture invented. Being deliberately wrong about the PRODUCT does not license being wrong about the
CITATION. It now cites extdeps.printing.bambu_studio -- real, in the same family, and genuinely not
the printer because it is the SLICER, so the fixture is a mis-registration someone could plausibly
make. The floor itself was clean through this: executed=3540 passed=3465 claims_failed=0
verdict=FloorClean, with every witness here planned-and-passed.

THAT REFUSAL ALSO FALSIFIED AN ANNOTATION IN THIS SAME CHANGE. A draft of the sibling file recorded
the catalog ref as "resolvable-in-principle, unresolved-in-evidence", reasoning that resolving it
needed an expensive decl_facts pool scan. False: the declarations phase resolves every cited module
path in the corpus and is what refused the fixture above. The check claimed missing was the check
that failed the PR. Both annotations now state the ref is a GATED citation. Understating a rung is
not the safe direction of the same error as inflating it -- a fabricated gap invites someone to build
what already exists.

Compile: 35 blocking, all in pre-existing files, none in any file touched here.
Witnesses: 11/11 green by direct execution (8 gating + 3 non-gating seal), subject digests verified
unchanged across the run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TuCmz2HjuYzP6GWLgw11E4
The arrival section carried an abstract pipeline. What the operator needs at the bench today is the
ORDER, because the ordering is the entire content: of the seven steps, four capture facts that no
later measurement can reconstruct, and they are cheap only while the parts are still on the machines.

The irreversible one is binding each coupon to its printer and spool BEFORE it leaves the bed. The
two coupons are geometrically identical by design -- that is what makes them a controlled comparison
-- so once both are off their beds and on the same table there is nothing left to tell them apart.
Getting that step wrong does not degrade the experiment, it voids it.

Also written down: label before power-on and label before loading, because identity is ALLOCATED at
individuation rather than derived from a serial read later; and the A1/B1 then A2/B2 structure, since
two copies on one plate answer bed-position variation while two executions answer print-to-print
variation, and conflating them attributes a machine difference to a corner of a build plate.

Explicitly excluded: every dimension, compensation constant and which-machine-is-better judgement.
Those are measurements and they are all still available tomorrow. Only four steps expire.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TuCmz2HjuYzP6GWLgw11E4
@gunbai-bot
gunbai-bot Bot merged commit 419a797 into main Sep 3, 2026
7 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/crisp-ibex-710 branch September 3, 2026 10:00
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