Skip to content

Add the public native US survey release entry - #996

Draft
MaxGhenis wants to merge 519 commits into
mainfrom
native-release-entry-20260923
Draft

MaxGhenis wants to merge 519 commits into
mainfrom
native-release-entry-20260923

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Adds build_native_survey_release, an in-process native US candidate entry.
It authenticates the live issued owner, closes options, verifies the expected
consumer identity, projects native inputs and checks coverage before creating
the release directory or materializing targets. It then uses the maintained
target compilation and dense/L0 solve, attaches weights to projected inputs,
checks fit and logical H5 readback, and writes a write-once native manifest.
The candidate remains non-release-eligible; outstanding qualifications are
explicit, and poverty remains comparison-only.

Review fixes validate finite solve settings and loss-multiplier families early,
rehash installed RECORD files, check loaded import origins, and recheck the
consumer and outputs before the manifest. Namespace imports now accept every
verified search location, including symlinked installs, while continuing to check file-backed descendants.
Failed directory setup preserves paths whose ownership is uncertain. File
hashing rejects nonregular files and closes descriptors even when wrapping
fails; manifest writing has the same descriptor ownership protection.

native-releases and the release directory are created and opened relative
to held descriptors, and the manifest is published through them. <out> and
any missing parents are created and opened by path, then checked for their
canonical location; the final reopen detects ancestor swaps but does not
prevent them. Diagnostics and H5 still use ordinary paths, and portable
mkdir/open leaves a creation-to-open gap: exclusive control of the output tree
is required. Final
checks refuse detected substitutions; they do not prevent earlier redirected
writes. Temporary-file cleanup is best-effort after success and failure.

Validation in the engine-free lane environment:

  • 237 native-release-entry tests passed, including synthetic namespace imports
    under copied and symlinked installs, spoofed namespace locations, directory
    substitutions, descriptor failure cleanup, every capability check, every
    constructor and all maintained package mappings.
  • 259 related readback, consumer-propagation, calibration-attachment,
    export-contract and native-handoff tests passed: 496 targeted tests total.
  • CI test-group verification, its 15 stdlib tests, Ruff and diff checks passed.

The US extra is absent here, so a full import of the pinned PolicyEngine-US
2.2.1 remains unrun. A probe on real uv installs of 2.2.1 (clone and symlink
link modes) accepted its namespace layout without executing PolicyEngine-US
code, and refused outside or mirrored namespace directories. These invented tests do not establish a successful public native
build: that still requires a genuine issued owner, admitted consumer runtime
and closed native input profile, followed by actual calibration and comparison
qualification. No actual-data or full-scale runs were performed.

🤖 Generated with Claude Code

MaxGhenis and others added 30 commits September 13, 2026 23:24
The fixture registered its two recipient kernels into the issued financial
run's own registry, which the run seals at issuance and re-checks in
check_atomic_survey_financial_run, so every test errored with
FINANCIAL_KERNEL_REGISTRY_CHANGED. Production (graph_survey_puf55)
composes a private KernelRegistry over the run's kernels; the fixture now
does the same. The last-owner mutation test also accepts the
node-population refusal that now fires first, as its siblings do.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…time

extended_status_host recorded its student _MEMBER_PINS patch on the outer
MonkeyPatch context after the generator had already patched the same
attribute, so on exit it restored the generator-era pins over the value
the module's first fixture installed, and that fixture's retained student
receipts failed STUDENT_CONTENT_CHANGED at its own teardown (attributed by
pytest to the last test, tax42). The patch now lives in its own context
nested inside the generator's lifetime, so undo order is LIFO.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
One rest job and both wheels 2/4 jobs hit GitHub's six-hour limit at 76-79%
of their shards (the alphabetically late survey-graph modules cluster there);
the partition is by file count, so a few heavy modules dominate a job. Six
and eight shards spread the heavy modules 13 and 9-10 per job instead of up
to 23, and every sharded pytest run now prints --durations=25 so the next
imbalance is visible in the job log. tools/ci_test_groups.py --verify and
its regression test pass.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…erified-lanes-20260910

# Conflicts:
#	PROGRESS.md
…erified-lanes-20260910

# Conflicts:
#	packages/microcosm-build/src/microcosm/build/uk_runtime/__init__.py
…erified-lanes-20260910

# Conflicts:
#	packages/microcosm-build/tests/test_spec_engine_country_bundles.py
Main's #896 resolves the local git code pin before any I/O in
run_uk_calibration, so four tests that previously refused or read back
before the pin now reach git rev-parse. In the installed-wheels CI job
the package lives under /tmp/wheels-venv, where no repository exists,
and test_readback_failure_updates_build_record_and_failed_attempt
failed with "Could not resolve the local git code pin". Give those four
tests the existing invented_code_pin fixture, as their siblings already
have; the unresolved-pin refusal test keeps its own failing pin.

Verified: the file passes 23/23 in the repository and 23/23 with a git
that exits 128 on PATH, which reproduces the wheels job condition.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Ship the native property and tax graph without the child-property
completion, keep the native CPU cap and remove the repeated-verification
cost instead of buying it, and make a from-scratch build plus
certification of the default the merge gate for this integration and a
standing check on main.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Records the lane's base, goal, evidence base and the two local constraints:
root out.md belongs to another lane, and the v5 cold run holds the machine.

Co-Authored-By: Claude Opus <noreply@anthropic.com>
_update_series boxed every value of a plain float, integer or boolean column
into a Python object and framed them one at a time; on pandas 3.0.3 a plain
column is a NumpyExtensionArray with no _data/_mask, so the fast masked path
never applied to it. _object_stream now builds the identical framed bytes --
the same 'object' dtype header, the same shape header, the same per-value
length prefixes and payloads -- with vectorised numpy, and returns None for
every column kind it cannot reproduce exactly, including a Categorical whose
values are an integer-coded view.

No digest value moves. test_graph_executor_series_stream compares the live
helper against a verbatim copy of the pre-change body at the byte level over
every column kind, the float specials, non-canonical NaN payloads, both int64
endpoints and a 200-frame random sweep. Measured 0.47 s -> 0.09 s on a
6,928 x 240 frame.

Co-Authored-By: Claude Opus <noreply@anthropic.com>
docs/us-native-verification-once.md states, per mechanism, the guarantee
today, the change, why the guarantee survives and the new cost class -- and
the two residuals the epoch's unconditional final re-validation exists to
close.

Co-Authored-By: Claude Opus <noreply@anthropic.com>
_records read the 2.4 GB of ACS person CSV inside csv_pus.zip one Python byte
at a time; with peek and columns.lines it was 57-65% of the admission phase in
every measured native run. It now finds terminators with bytes.find, counts
quote parity with bytes.count, and keeps each terminator cursor until the scan
passes it -- so an absent carriage return costs one search per 1 MiB block
rather than one per record, which is where the bulk of the win is.

The two ceilings are charged by _fence. A record no longer than the smaller of
the live ceilings cannot have violated either, because the token counter resets
at every record start; anything longer is replayed byte by byte, so the refusal
code and the byte it fires on stay the fence's own -- including the LF that
closes a CRLF record, which the fence charges against the record ceiling only.

test_us_acs_record_fence_scan compares the shipped fence against a verbatim
copy of the byte loop: every boundary case, every block-boundary case, every
ceiling on both sides, 4,500 randomised strings, 300 row-shaped inputs, and all
9,331 strings up to five bytes over the branching alphabet under each of five
ceiling settings -- 46,655 exhaustive comparisons. Measured on the real staged
archive: 10.8 MB/s -> 522.8 MB/s, digests identical.

Re-pins acs_native_coverage_binding._ACCEPTED for the changed module:
  475aa795c8a5b49a0dd3405a0877866dddd03012a1f2b9743447fab1fe85bcff
  -> 9ec68721a4cf480ef412c51ab354db9000eb7a7989e35e6e09b1574d88e8e49f
  (shasum -a 256 .../acs_person_coverage_authentication.py, after formatting)
The module's graph_implementation_inventory contract is unchanged: the rewrite
adds no _RESOURCE_CALLS name and no non-stdlib import.

Co-Authored-By: Claude Opus <noreply@anthropic.com>
executor.py re-derived source_content_key for every source a cold-executed
node declared, and keys._directory_identity read_bytes()es every file of the
tree: O(executed source-declaring nodes x source bytes), which on the native
graph is the 3.48 GiB source tree re-read per node.

run_graph now carries a _SourceIdentities cache in its own locals, populated by
the run-start pass as it reads. A cached key is reused only while the path's
stat signature -- (dev, ino, size, mtime_ns, ctime_ns) for a file, and for a
directory its own identity plus the relative name, type and identity of every
entry _directory_identity would walk -- is identical to the signature taken
both immediately before and immediately after the read that produced the key.
A derivation whose two signatures disagree is not cached at all.
source_content_key itself stays pure and uncached: three key and codec tests
call it twice on one path with the bytes changed in between.

Before the manifest is built, every source is re-derived in full with the cache
bypassed, written inline rather than through _source_paths_and_keys because a
build test counts calls to that code object. That closes the two cases a stat
signature cannot decide, and gives the executor a guarantee it never had: a
source changed during a node that declares none is now caught.

RunManifest gains source_identities, attached exactly like populations and
mass_ledgers -- repr=False, compare=False, outside content_addressed, outside
to_json, outside every node receipt and cache record.

test_graph_executor_source_identity pins the contract that had no test at all:
a source rewritten by its own node refuses and writes nothing to the store, a
file added to or removed from a directory source refuses, a same-length rewrite
with mtime restored refuses, a change during a source-free node refuses at run
end, and an unchanged source is read twice per run however many nodes declare
it. The graph suite falls from 108 s to 72 s.

Also records the real-archive record-fence parity receipt: both ACS person
members, 2.4 GB, 3,422,890 records, identical digests, 226.9 s -> 4.6 s.

Co-Authored-By: Claude Opus <noreply@anthropic.com>
Every borrow of AuthenticatedSurveyPopulationPreparation re-ran the whole
authentication: both source catalogues, the ACS native coverage binding (eight
full zip reads), the nested ASEC native population (seven files), the ten-file
roster re-hash and every pure seal -- once per executed node through the
population observer, and again inside every kernel that borrows it. The ASEC
native capsule did the same on every .frame access.

survey_population_preparation.verification_epoch() makes that happen once.
Inside an epoch each borrow still pays a cheap tier in full -- the live
authority and attached owner payloads, _encode(_producer()), and _file_stats
over the whole roster -- and the expensive tier is skipped only while a
signature is unchanged: the stat identity of every path the four foreign
verifications and _source_files re-read, the identity and length of every
borrowed payload, and a read-free witness of every live Frame's storage
(buffer address, shape, strides, dtype and writeable flag per column, index and
weight). A signature that moved is a memo miss, not a refusal: the complete
validation runs and raises exactly what it would have raised.

Leaving the epoch, at every nesting level, re-validates every memoised capsule
in full with the memo bypassed, so a change no signature can see -- an in-place
write into a live buffer, or a value written into a frozen plan row -- still
makes the run refuse before the caller receives anything. Outside an epoch
nothing is memoised and every existing borrow, refusal and trace-based mutation
test keeps its exact meaning; _validate and _validate_state are untouched.

The three foreign owners gain only a _verified_source_stats() helper naming the
paths their own verification re-reads. Their inventory contracts do not move.
The two capsule modules' unbound_uses digests do, because the new functions use
already-imported names in new scopes; both are re-derived through
graph_implementation._dependency_contract and recorded in PROGRESS.md.

Co-Authored-By: Claude Opus <noreply@anthropic.com>
run_atomic_survey_population and run_atomic_survey_financial now wrap their
whole body in survey_population_preparation.verification_epoch(). Every native
capsule the run borrows is authenticated in full once, reused while its sources
and live storage are provably unchanged, and re-authenticated in full before
the run returns. The financial run's prefix opens a nested epoch; each closes
with its own full re-validation.

Both commits are an indentation plus one 'with' line. Proven mechanically: the
statement lists of both function bodies parse to identical ASTs before and
after (50 statements and 102 statements), the argument lists are unchanged, the
docstrings stay outside the wrapper, and both files were ruff-format clean at
the base so every hunk lies inside the wrapped function. Keeping the body in
its own function matters: a build test asserts
caller.f_code is runner.run_atomic_survey_population.__code__.

The epoch's exit closes the nested capsule's epoch first, so this owner's final
validation reaches the nested population's complete file check rather than its
memo, and collects both refusals so neither can be lost to the other in a
finally block. A foreign owner's error raised by a deferred borrow is
translated exactly as _checked translates it, instead of escaping raw.

test_us_native_verify_once_epoch: 17 tests. Validated once and reused (one
_source_files pass for six borrows, five memo hits); the producer encoding
never memoised; every on-disk mutation -- append, truncate, same-length rewrite
with mtime restored, a file added to a source directory, a touch -- refusing at
the borrow that follows it AND again when the epoch declines to close over it;
a signature miss outside the roster re-running without refusing; a change no
signature can see refusing at the close; a failing body finalizing nothing; and
nested epochs finalizing at every level.

Also adopts the change in docs/validation-cost-and-borrow-boundaries.md, which
recorded this optimization as proposed rather than adopted, and corrects the
codecs docstring that called the executor's check post-run.

Co-Authored-By: Claude Opus <noreply@anthropic.com>
Co-Authored-By: Claude Opus <noreply@anthropic.com>
The frame-witness bridge into the preparation owner is module-internal; naming
it without the underscore made it look like an owner API. Renaming it moves the
module's unbound_uses digest, because that digest keys each use site by its
enclosing scope, so the inventory contract is re-derived through the module's
own generator:
  71463df4f645cd2a98f537a212187b4d1e52bffcc4d2317defe6968d7f287608
  -> 7bb20439da26f75b48551e21e304c4bb7f3983ee07ef78ed804411640d58cdf4
All ten stage manifests still build.

Co-Authored-By: Claude Opus <noreply@anthropic.com>
Co-Authored-By: Claude Opus <noreply@anthropic.com>
MaxGhenis and others added 30 commits September 20, 2026 11:05
Reduce the two published CPS ASEC disability income slots to one
non-workers-compensation leaf by borrowing the retirement-detail owner's
already-qualified DIS literals and the retired eCPS arithmetic. No raw
member is read, no source authority is issued and nothing is completed.

The archived parameter dictionary and
derive_us_disability_benefits_from_asec are reused rather than restated,
and the workers' compensation exclusion is bound to the printed meaning
of code 1 rather than to the bare integer. A slot resolves only through
a closed vocabulary; NIU, missing, under-15 and contradictory slots stay
unknown instead of becoming an observed zero, and a "yes" receipt with
no populated source stays unknown too. The archived arithmetic's reading
is recorded beside the qualified leaf and never adopted.

Conditional allocation provenance is evaluated against each flag's own
printed universe and never qualifies a receipt; topcode flags describe
only the dollars the leaf admits. The thin attachment copies one
qualified row to every clone of its original source person by identity
join, takes no draw, mutates no receiving cell, and leaves rows on an
arm this source never observes explicitly unknown rather than zero.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Independent review found four defects in the adapter and four claims the
code did not support.

A workers' compensation slot whose amount literal was missing was being
admitted as a known zero, so the module contradicted its own rule that a
missing cell stays unknown. The exclusion now applies only to the two
statuses a coherent readable slot can carry.

The implementation fence bound the detail owner's seal but not its
qualifier or literal projection, so a swapped qualifier could have handed
over doctored amounts, and it listed constants by hand, so REPORTING_AGE
and others could be retuned after import without refusal. It now collects
every module-level constant and binds the borrowed callables this module
actually depends on, including the routing owner's receipt, literal and
code-frame helpers.

The routing owner's family allocation reading is universe-blind by its
own charter, so a flag read outside its printed universe was standing as
this family's allocation answer beside a per-flag label that said the
opposite. The two scopes are now reported under separate names.

Tests cover each fix, prove the archived function itself is called with
its archived parameters rather than merely reproduced, mutate the
borrowed table for real between the two seals, and check that every
attached cell is the source person's own qualified cell. The module
docstring and the doc drop the overbroad "reads no raw member" and
"produced a zero for every row" claims.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A second independent review confirmed the first round's four fixes and
found three more, all of which predate those fixes.

The constant sweep stored another module's live mapping by reference, so
retuning the archived parameter dictionary in place mutated the snapshot
with it and passed its own equality check. Constants are now detached
before they are sealed.

The implementation digest was taken at call time, so a file edited after
import left the loaded functions passing the fence while the recorded
`implementation_sha256` named bytes that never ran. The digest is now
pinned at import and compared, so such an edit refuses.

The fence bound the detail owner's qualifier but not its member capture
or amount comparison. The owner cross-checks the retained DIS amounts
against the money owner, but `DIS_YN`, `DIS_SC1/2` and the allocation and
topcode literals reach this leaf from the capture alone, so a replaced
capture could have turned a workers' compensation slot into an admitted
one. The capture and comparison path, the routing owner's capture and
digest helpers, and the archived function's own input guard are now bound
too. The doc says plainly that this list is enumerated, not a transitive
closure, and names the capture boundary a consumer should know about.

Topcoding reads as "some admitted slot is topcoded", so one readable flag
of 1 now settles it rather than being erased by a second admitted slot
whose flag cannot be read.

The evidence no longer claims `raw_member_read: False` from the public
qualifier, which does cause a read through its owner; it records
`adds_raw_member_reader` and names the capture owner instead. The
previous commit message's "the borrowed callables this module actually
depends on" overstated an enumerated list, and the first commit's "No raw
member is read" was true only of the pure entry points.

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

A third independent review confirmed the second round's fixes and found
one more defect: the receiver supplies its person table through its own
callable, which runs after the attachment's entry check, so a receiver
that retuned a module constant between the two could have had its own
name used for the canonical leaf. The attachment now rechecks the
implementation before returning.

The implementation pin attests this file as read at the end of its own
import; it cannot attest the window between the loader's read and that
one, and the evidence scope and the doc now say so rather than claiming
"the bytes as imported".

Three descriptions were more general than the code: the owner
cross-checks only the two retained DIS amounts against the money owner,
not the receipt, source and flag literals; the archived arithmetic read
whatever a never-asked row's literals held, usually but not always zero;
and a receipt answer alone does not settle a slot, since a "no" or NIU
answer beside a nonzero amount or a populated source code is a
contradiction rather than a nonreceipt.

New tests close the gaps the review named: the published source-code
table is pinned by value instead of read back from the owner, the age-15
boundary and receipt-universe drift are exercised, the second slot
excludes on the same terms as the first, a contradictory out-of-universe
row is shown carrying a positive archived reading that is still not
adopted, a definite allocation is shown outranking an unresolved flag
where the owner's universe-blind reading does not, clone transport is
shown following identity rather than row order, and a hostile receiver
is shown being refused.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A fourth independent review found that binding a class object leaves its
initializer swappable: the identity survives, so the implementation fence
passed while the constructor this module calls after its last check could
be replaced by whoever supplied the receiver, whose own table() runs
inside the attachment. The fence now seals each returned type's own
methods, the attachment is constructed before the terminal checks, and
both results are required to have kept the payload they were handed.

The archived replay runs over the four fields as the owner parsed them,
so it is evaluable only where each read inside its own printed domain,
while the retired function accepted any finite number. A source code
outside the published table is therefore a row the old pipeline would
have summed and this replay reports as unevaluable. The docstring, the
doc and a new test say so; the previous "whatever it read is recorded"
wording did not.

Two further descriptions are narrowed to what the code establishes: the
routing owner answers an unresolved flag literal before a nonzero flag
outside its universe, so its universe-blind reading is not unconditionally
a publisher allocation; and "usually zero" claimed a frequency no static
code or invented fixture establishes. The third commit's claim that the
receiver fence was closed was true only of the path its test exercised.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`native_survey_handoff.REQUIRED_RELEASE_EVIDENCE` lists
`national_and_cd_target_fit`, and nothing produced it. The canonical
two-artifact yardstick, `tools/score_us_release_head_to_head.py`, emitted
`family`, `entity`, `value_basis` and `period` per fiscal row and no
geographic identifier at all, so a national-versus-congressional-district
reading of a head-to-head could not be computed from the scorecard even
after a real run — while the native measurement kernel that will produce
the candidate is already geography-scoped by construction
(`graph_fiscal_measurement._LEVELS`, `FiscalGeographyScope`).

Add `us_runtime/target_geography_view`: a pure classification of one
compiled target row into the national/state/congressional_district view its
declared evidence names. It prefers explicit declared level evidence, in the
order the compiler produces it (the calibration hierarchy's geography tier,
then `ledger_geography_level`, then `geography_scope`), renames ledger's
`country` to `national` exactly as `fiscal_targets.py:2816-2826` already
does, and reuses the shared
`microcosm.data.us_critical_targets.is_congressional_district_target` rather
than restating CD membership. A row no declared evidence places is reported
`unresolved` and kept out of the three views: labelling it national would
make the national view look better than the artifact is. A disagreement
between the shared CD classifier and an explicit declared level is counted
and reported, never silently resolved.

Wire it through the scorecard: per-row `geography_level`/`geography_id` and
their provenance, a `by_geography_level` rollup and a
`geography_view_resolution` receipt on each artifact, a comparative
`by_geography_level` block on the head-to-head, and Markdown sections for
both. Per-view contributions are shares of the same
`relative_error_loss` aggregate, so they sum to it exactly; the tests pin
that, the counter reconciliation, the refusal routes, and equality with the
frozen kernel's scope vocabulary. Schema version 3 -> 4.

No gate, threshold, tolerance, band or verdict is added. The scorecard stays
evidence for the owner's flip decision; this only decomposes that evidence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`experiments/replacement_scorecard/incumbent_48b9d479.json` is an
incumbent-only run with `comparison: null`, which is the shape published
before a candidate exists. Pin that path: the per-artifact view rollup and
its unresolved count must render there too, and the comparative section must
not, or the `national_and_cd_target_fit` evidence would only appear once a
candidate is available.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Root reviewed e45793e and did not adopt it:
`target_geography_view.us_target_geography_view` chose a geography level
from one piece of evidence and then searched an ordered metadata key list
(`ledger_geography_id`, `congressional_district_geoid`, `state_fips`) that
consulted neither the level nor the declaration that named it. A row whose
hierarchy sat below the advertised views would have reported that sub-state
id as a state's, and a district row without its own geoid would have
reported the parent `state_fips` the compiler derives from that geoid
(`fiscal_targets.py:2825-2830`).

That search was unreachable for every spec the US compiler can currently
emit: each reference carries a hierarchy seed, `_calibration_hierarchy`
refuses an empty or non-single-valued fact geography
(`ledger_targets.py:934-952`), and `HierarchyNode` refuses an empty id, so
every compiled row resolves through `hierarchy_geography` with a bound id.
No scorecard's counts change. This is a contract repair that closes the
hole before a producer reaches it, and the commit claims nothing more.

An identifier is now read only from a declaration whose own declared level
is the row's resolved level -- hierarchy geography, then the ledger copy,
then the key that level owns -- and a row with none keeps an empty
identifier with `geography_id_source` `none` rather than borrowing one.
Every declaration at the level stays visible in `declared_geography_ids`.

Two encodings exist and are kept apart rather than reconciled. The prefixed
census GEOID is one ledger field read twice (`hierarchy.geography.id` and
`metadata['ledger_geography_id']`), so those two are comparable and
`geography_id_declarations_conflict` asserts they agree -- a defensive
invariant expected to read zero, labelled as such in the artifact note. The
bare `state_fips` / `congressional_district_geoid` is a prefix-stripped
restatement, never compared against a prefixed id and never a conflict; it
is also not interchangeable, because both CD vintage prefixes strip to the
same four digits. `"0400000US"` is an unnamed literal in four production
modules with no shared constant, so no conversion is attempted here.

Because of that, the rollup counts distinct *canonical* ids and reports
`rows_with_bare_geography_id` and `rows_without_geography_id` beside them,
with per-view `geography_id_source_counts`: mixing the two spellings in one
set would count one area twice, which is the same class of wrong count the
level binding exists to prevent. Markdown states the new counts in both the
per-artifact and comparison sections. Schema version 4 -> 5.

No gate, threshold, tolerance, band or verdict is added, and the scoring
path, the loss definition and the per-target error rows are untouched.

TESTS NOT EXECUTED. Free disk measured 8.54 GiB falling to 7.76 GiB during
this work, below the operator's 10 GiB floor, and root notices -180/-184
hold new test runs while it is; root's continuity instruction for this job
is code and static review only. Eight new tests and two fixture updates are
authored and reviewed but unrun; the bounded no-engine harness is staged at
893/native-comparison-geography-id-binding-20260920/run_tests.py with the
exact invocation recorded in the lane report. Static checks that were run:
`ast.parse` on all three edited modules, repo-wide `ruff check` (passes),
`ruff format --check` on the touched files (clean), and
`tools/ci_test_groups.py --verify` (verification=ok).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The inline comment on `_CANONICAL_GEOGRAPHY_ID_SOURCES` called a difference
between the two copies "a real conflict" without saying why. Name the
upstream refusal (`ledger_targets.py:934-952`) that makes it an invariant
violation rather than an encoding difference, matching the property
docstring and the artifact note.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`_declared_geography_ids` returns `(source, identifier)` pairs, and the
binding unpacked the first pair as `geography_id, geography_id_source`, so
every resolved row reported its identifier as the source name and its
source as the identifier: a California state row came out with
`geography_id="state_fips"` and `geography_id_source="06"`. The empty
branch was reversed the same way, so an unbound row reported
`geography_id="none"` rather than `""` -- which would also have put the
string "none" into a view's distinct-area set.

Caught by the bounded no-engine suite, which had been held while free disk
sat below the 10 GiB floor and ran once that cleared (21.45 GiB free): nine
tests failed on the swap, including the pre-existing
`test_view_resolution_routes_and_refusals`, whose geography_id assertions
predate this branch's identifier work.

After the fix the whole file is green under the same envelope: 54 tests, 0
failures, 0 errors, 4 pre-existing `requires_us` skips, 24.45 sampled CPU
seconds, 39.71 wall seconds, 460,275,712 bytes peak RSS, and zero guard
denials for country imports, network, child processes, external data and
external writes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Source-qualified SS report completion for selected original ASEC and ACS
people: full-original ASEC DESIGN donors, real categorical fit/probability
artifacts, reason-constrained completion, and a no-fit empty-recipient path.
No canonical beneficiary writes and no release qualification.

The probability and normal-branch report nodes join the donor version: the
graph compiler makes a FILTER depend on every member of its base version, so
a fit consumer on the full-source version cycled through the donor FILTER
(graph-successor3). Successor4 passed 6/6 under the admitted harness; the
full graph and source files pass 32/32.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The keep-all and placement nodes named every entity ID and person membership
column in their Slices. Those columns arrive in the executor's structural
view and have no owner in the compiled declaration, so the first genuine
Stage B run refused at compile: placement_receiving read person.person_id,
which no node owns in the canonical state version. Declare only the
qualified person values and candidate outputs, and omit an entity with
neither. The host compile test now owns no structural column in its fixture
CREATE, matching the real host, and asserts the slices name none.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The genuine Stage B successor3 run reached the enrichment compile and
refused with CURRENT_SURVEY_AMOUNTS_PREFIX_DECLARATION_OR_KEY: 113 parent
nodes kept their declarations and kernel hashes but changed keys, starting
at survey_puf55.receiving. compile_graph makes a structural node depend on
every non-structural member of its base version, and that FILTER's base is
the financial version, so the arm-zero recipient projection, matrices and
fixed-input nodes declared on the financial version joined the authenticated
parent's predecessor closure.

The original arm now opens survey_puf55.original_source_version, a keep-all
FILTER off the financial version, and declares its three source nodes there.
Arm-one declarations are byte-identical. The host reconstructs the version
through the binding, and a new test compiles a parent FILTER with and
without the original arm and asserts its predecessors do not change (and
that the old binding did change them).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The genuine Stage B successor4 run passed the prefix invariant and executed
the enrichment graph to the terminal observation, where the original
placement cut refused PUF55_ORIGINAL_PLACEMENT_ARM_ONE_OUTPUT_OWNER. A replay
diagnostic showed every arm-one output column at the terminal owned by
survey_geography.canonical_state_version: population.patch gives a
structural version ownership of every carried cell, so the receiving owner
can never equal survey_puf55.attach once a FILTER sits between arm one and
the terminal.

candidate_outputs now accepts the arm-one attach node or the receiving
version as the owner and, when the version re-owned the cells, requires the
carried values to equal the arm-one values (ARM_ONE_OUTPUT_CARRIED). Any
other owner still refuses. A new test covers the accepted re-owned shape,
a changed carried value, and a later owner.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
dataclasses.replace shares the receiving frame between the reowned inputs,
so the value-mutation case must run after the later-owner case.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…acement artifact

The genuine Stage B successor6 run executed the original-arm enrichment cold,
ran the required replay, and refused PUF55_ORIGINAL_PLACEMENT_PLACEMENT_ARTIFACTS
in the host's independent reconstruction: the persisted placement document
differed from the recomputed one in exactly one field, the third
input_population_stamps entry (the receiving terminal). _stamp is an
in-process mutation seal over replay-variant state and is already verified
before and after the document is built; persisting it made the artifact
non-reproducible under replay. The document now records the three input
population versions instead. A new test permutes the receiving table columns
(changing the seal, not the values) and asserts byte-identical artifacts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
placement_result returns a columns/document pair, not a KernelResult.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Adds build_native_survey_release beside the development handoff: owner
authentication first, closed native options, exact consumer identity
comparison, live projection, shared targets, a pure input gate, admitted
constructors for materialization, the shared solve and a verified logical
H5. The manifest is never release-eligible and lists outstanding
qualifications.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Wrong-parent export tests refuse before the writer for changed retained
cells, roles, household IDs, membership, column roster, ID dtype, strata
and metadata, and a readback cannot reuse the true parent's binding. A
further test documents that the pure comparator cannot distinguish parents
that differ only outside the retained scope, which is why the entry binds
the retained projection object and its whole-frame digests.

Adds the native release entry guide, links it from the development handoff
guide and CLAUDE.md, adds a changelog fragment, and forbids main/_main in
the forged-owner ordering test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two public-entry wiring tests: dataset bytes replaced during the final owner
check refuse with NATIVE_RELEASE_DATASET_CHANGED, and an effective SPM
identity that changes or cannot be resolved after the writer refuses with
NATIVE_RELEASE_CONSUMER_CHANGED. Neither writes native_release_manifest.json.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The entry now refuses before consumer admission when <out>/native-releases
is a symlink or a file, so outputs cannot be redirected outside --out. The
handoff guide also names the target-parity gate among the parts of step 5
the entry covers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The native entry is called in process, so the caller's working directory
may be another repository or none. Its manifest's builder_source now asks
git about the checkout the tool file was loaded from. The legacy helpers
are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From review job 20260923-084643-native-release-entry-review (Opus 5.5):

- Solve settings are checked at parsing (positive epochs and learning
  rate, finite max weight ratio of at least 1, finite non-negative L2 and
  L0 share, non-negative seed), and an unknown loss family refuses before
  the output directory, instead of failing after materialization.
- Consumer identity re-hashes every hashed RECORD row on disk (RECORD is
  parsed directly, since Distribution.files drops missing files), refuses
  editable installs, and records input defaults so defaults added after
  admission change the identity.
- Constructor resolution, input-profile and writer/HDF library errors
  become codes without private detail.
- The native root is rechecked around directory creation, diagnostics
  bytes are rechecked with the dataset after the final owner check, and
  the manifest is hard-linked into place so an existing one is never
  replaced.
- Docs now state which reused helpers keep their own errors, scope the
  download claim to this entry's code, and describe the None defaults for
  legacy source-stage gates accurately.
- New tests cover unknown values, projection report binding, export
  binding, sparse public wiring with sockets disabled, and the dotted
  release ID and manifest pin refusals.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…umer imports

Address the second independent review of the native release entry:

- Create <out>/native-releases/<release-id> relative to directory
  descriptors opened with O_NOFOLLOW, require the canonical path to name the
  created inode, probe hard-link support before the solve, and remove only
  the empty directory this build created when either check fails.
- Reopen the created directory before the manifest, refuse with
  NATIVE_RELEASE_DIRECTORY_CHANGED if its path now names another directory,
  and hash the dataset and diagnostics and write the manifest through it.
- Make the manifest writer exclusive on its temporary file, remove the
  temporary name on every path, and code stale-temporary, link and I/O
  failures.
- Require every loaded module of a roster distribution to come from a
  verified RECORD file, and accept an absent distribution only while none of
  its import packages is loaded.
- Compare the consumer's in-memory state after the final owner I/O, keep the
  original refusal as the cause of NATIVE_RELEASE_CONSUMER_CHANGED, code an
  unparseable RECORD, and drop an unreachable solve-option check.
- Correct the guide and CLAUDE.md claims the review found overstated, and
  add tests for each guard the review found untested.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tive release entry

REVIEW-3 O1: a consumer namespace package now needs nonempty namespace
metadata, and every search location must be a matching package directory
holding verified distribution files; file-backed descendants stay checked.

F1: failed directory creation or hard-link probing no longer removes a
directory by pathname, so a renamed or replaced directory survives. F2:
hashing rejects nonregular files, opens nonblocking so a FIFO cannot hang
it, and always closes its raw descriptor; the manifest writer closes its
descriptor when fdopen fails. Docs narrow the descriptor-protection claims
and state that temporary cleanup is best-effort.

227 native-release-entry tests and 259 related readback, propagation,
attachment, export-contract and handoff tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…riptor claims

REVIEW-4 N1: under uv --link-mode symlink every installed file resolves
into the cache, so a namespace search location (a real site-packages
directory) was never an ancestor of a resolved verified file and the
consumer check refused pe-us 2.2.1. A verified RECORD row now also
authenticates the directories it names under the install root, resolved
once per directory. Unhashed rows, mirrors, unrecorded siblings and
outside directories still refuse; tests cover both layouts.

N2/N3: the changelog, builder comments and docs no longer say every
directory operation uses no-follow descriptors. native-releases and the
release directory are descriptor-relative; <out> is created by path and
checked for its canonical location. Step 8 now names directory
replacements and the canonical-path refusal code correctly.

237 release-entry tests and 259 related tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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