Skip to content

[NO-MERGE] evidence: independently reproduce ULX3S LSC-1 bitstream - #117

Merged
Th0rgal merged 10 commits into
mainfrom
codex/lsc1-ulx3s-cleanroom-receipt
Sep 7, 2026
Merged

[NO-MERGE] evidence: independently reproduce ULX3S LSC-1 bitstream#117
Th0rgal merged 10 commits into
mainfrom
codex/lsc1-ulx3s-cleanroom-receipt

Conversation

@Th0rgal

@Th0rgal Th0rgal commented Sep 6, 2026

Copy link
Copy Markdown
Member

Summary

  • records two independent detached-worktree builds of source fde1b885a56b98391833f4632676f14d1e3e2f9c
  • binds exact Yosys/nextpnr/ecppack versions, nextpnr options, source tree/manifests, raw build-receipt hashes, and 10 MHz timing results
  • verifies both .bit, .config, and .svf outputs are byte-identical to each other and the immutable archive on exact base 5610ea221dd82b5749690043e8c3665b2be9ced8
  • adds a fail-closed verifier and focused mutation regressions

Reproduction result

Both isolated builds exited 0 and nextpnr reported Program finished normally. Both complete source manifests bind all build inputs to fde1b885…. Both timing receipts report 15.32 MHz achieved and PASS at the required 10.00 MHz core clock.

Artifact SHA-256 values reproduced in both runs:

  • .bit: 226514183384b875821426b8c4d338508d8cff08cd12cb8e39c9162db37e3b9e
  • .config: 0737bbafae6704139ad9de2669a4e43f64d02644ce7cb9fc7bef336b28b7bf6b
  • .svf: 0ad6510adeb1afbc3b20bdbc96528211a2d2e38ebcee398fdeb82acb3b1ad0ee

Validation

  • both ./fpga/ulx3s/build_packet_uart.sh executions — exit 0
  • per-run sha256sum -c SHA256SUMS — exit 0 for all three artifacts
  • byte comparisons run-to-run and run-to-archive — exit 0 for .bit, .config, .svf
  • python3 tools/verify_lsc1_ulx3s_reproduction.py — exit 0
  • python3 -m pytest -q test/test_lsc1_ulx3s_reproduction.py test/test_lsc1_fpga_packet_evidence.py test/test_ulx3s_packet_build_recipe.py — exit 0; 22 passed, 34 subtests passed
  • make -C test/packet_frontend sim — exit 0
  • make lean — exit 0; both Lean builds succeeded and all configured mutation families were killed
  • git diff --cached --check before commit — exit 0

An exploratory make -C test/packet_frontend clean all exited 2 because that Makefile has no all target; the valid repository target sim was then run and passed.

Boundaries

This is host-build reproducibility evidence only for the full LSC-1 host-prepared packet endpoint. It adds no host fetch or memory expansion and covers no later roadmap work. Executable-model, Lean, authored-RTL, generated-netlist, place-and-route, and physical-hardware evidence remain separate. No board was attached, programmed, or observed. This makes no physical, universal/unbounded, or end-to-end claim.

Review only: intentionally NO-MERGE. Do not merge this PR.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 6, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-07T04:28:29.725784Z 65890eb New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7fb99409ea

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tools/verify_lsc1_ulx3s_reproduction.py Outdated
require(r.get("base_commit") == BASE, "base commit")
source = r.get("build_source", {})
require(source == {"commit": SOURCE, "tree": "87462c2c698c43318df8b9a4db78c0c6ca9de251", "inputs_match_revision": True}, "source identity")
tree = subprocess.check_output(["git", "rev-parse", f"{SOURCE}^{{tree}}"], cwd=ROOT, text=True).strip()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Make the pinned source commit available to the verifier

In a clean checkout of this commit, fde1b885a56b98391833f4632676f14d1e3e2f9c is neither reachable from a ref nor present as a Git object, so this rev-parse raises CalledProcessError. Consequently the standalone verifier exits 1 and all eight newly added tests fail before validating their receipts. Preserve a reachable source object or validate the archived source manifest without depending on an unavailable detached-worktree commit.

Useful? React with 👍 / 👎.

Comment thread tools/verify_lsc1_ulx3s_reproduction.py Outdated
Comment on lines +88 to +89
require(run.get("raw_receipt_sha256") == RAW_RECEIPTS[run["id"]], "raw receipt hashes")
require(run.get("artifacts") == ARTIFACTS, "run artifact hashes")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Verify the independent run files, not only their claims

For reviewers relying on this verifier to substantiate the two clean builds, this check only compares receipt fields with constants added in the same commit. A repo-wide tracked-file search finds no per-run clean-build-* logs or artifacts to hash, and the recorded Yosys/nextpnr digests do not match the sole pre-existing archived logs. Thus verify() can report success without inspecting any output from either purported reproduction run; archive and hash the actual per-run receipts and artifacts before accepting the reproduction conclusion.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a9ce903a2c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tools/verify_lsc1_ulx3s_reproduction.py Outdated
require(r.get("base_commit") == BASE, "base commit")
source = r.get("build_source", {})
require(source == {"commit": SOURCE, "tree": SOURCE_TREE, "inputs_match_revision": True}, "source identity")
require(git("rev-parse", f"{SOURCE}^{{tree}}") == SOURCE_TREE, "source tree object")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Anchor verification to the reviewed commit's history

Fresh evidence shows that the replacement anchor adc3e2c5b86fb08e1b0225573486ae08af4ac194 is still absent from this reviewed commit's ancestry: 8605446 has sole parent 5610ea2, while the anchor is an intermediate commit on a separate history. In a clean checkout containing only the reviewed commit and its ancestors—such as after a squash merge or deletion of the PR branch—this rev-parse raises CalledProcessError, causing the newly added workflow-check verifier to fail before checking the archived runs; the packet-evidence verifier now depends on the same unavailable object. Use a reachable ancestor (the recorded build inputs are also present at 5610ea2) or preserve the manifest without requiring this detached object.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ebf087429a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tools/verify_lsc1_ulx3s_reproduction.py Outdated
"malformed source manifest")
require(fields[1] not in entries, f"duplicate source input {fields[1]}")
entries[fields[1]] = fields[0]
require(len(entries) == 25, "complete source manifest")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Validate the manifest's exact input names

Checking only len(entries) == 25 allows any 25 files from the base tree to pass as a complete source manifest. I replaced asic_core/rtl/gf128_mul_bitstream.sv with a correctly hashed README.md, updated the receipt hash, and verify() still returned success, so evidence can omit an RTL, constraint, or build-script input while retaining the reproduction conclusion. Require the entry-name set to equal the packet recipe's known inputs, as the existing PACKET_BUILD_INPUTS check does in the physical-evidence verifier.

Useful? React with 👍 / 👎.

Comment thread test/test_lsc1_ulx3s_reproduction.py Outdated
Comment on lines +109 to +110
subprocess.run(["git", "clone", "--bare", "--shared", str(source), str(staging)],
check=True, stdout=subprocess.DEVNULL)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid a shared staging clone for the squash regression

When make check runs from a blob-filtered checkout, this shared bare clone references the source object store but does not inherit its promisor remote, so the later --no-local clone fails while packing an absent historical blob (git clone -h describes --shared as “setup as shared repository”). I reproduced the new test failing with fatal: bad tree object before either verifier ran; the executable-model CI job currently uses fetch-depth: 0, so this affects partial/local checkouts rather than that full-clone lane. Build the staging repository without --shared, or otherwise preserve the partial-clone fetch configuration.

Useful? React with 👍 / 👎.

@Th0rgal

Th0rgal commented Sep 6, 2026

Copy link
Copy Markdown
Member Author

Successor verification for a15dab2022ac6e93786058d815851c35cb3b5038 (fast-forwarded from reviewed head d5ca3d83e0fce0eaffa8c3d8bc4db0e583715595):

  • Reproduced the reported pre-verifier failure from a genuine network-backed git clone --filter=blob:none checkout: the first git clone --bare --no-local could not obtain a promised blob.
  • PYTHONPATH=. python3 test/test_lsc1_ulx3s_reproduction.py ReproductionReceiptTest.test_post_squash_checkout_accepts_from_blob_filtered_source -v — PASS; the squash-style checkout ran both evidence verifiers successfully.
  • make workflow-check — PASS (including the exact manifest-name substitution rejection and evidence-binding mutation tests).
  • make check — PASS after regenerating and checking SHA256SUMS; 401 simulation tests passed (1 environment-specific skip), plus all remaining repository gates.
  • git diff --check and python3 tools/generate_checksums.py --check — PASS before commit.

The change only repairs test-fixture object materialization before independent bare clones and updates the tracked checksum. It does not broaden the evidence claim beyond host-side authored-RTL synthesis/logical-netlist/P&R reproduction; it adds no physical-board, E2E, LSC-1µ, LSC1-06+, universal-correspondence, or host fetch/memory claim.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9d7032338a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread test/test_lsc1_ulx3s_reproduction.py Outdated
def materialize_promised_objects(source: Path) -> None:
"""Make an independent clone safe to serve without lazy fetching."""
promisor = subprocess.run(
["git", "-C", str(source), "config", "--get", "remote.origin.promisor"],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Materialize the configured promisor remote

In a valid blob-filtered checkout whose promisor remote is not named origin (for example, git clone --origin upstream --filter=blob:none ...), this probe returns nonzero and skips materialization. Under the GIT_NO_LAZY_FETCH=1 context modeled later in this test, the subsequent git clone --bare --no-local then fails while packing a missing promised blob. Fresh evidence after the prior --shared fix is that this reproduces with remote.upstream.promisor=true; git clone -h documents that --origin <name> can use a name other than origin. Discover and fetch the configured promisor remote instead of hard-coding origin.

Useful? React with 👍 / 👎.

Comment thread tools/verify_lsc1_ulx3s_reproduction.py Outdated
for key in ("host_fetch", "memory_expansion", "physical_hardware", "end_to_end", "universal_or_unbounded", "later_roadmap_work"):
require(scope.get(key) is False, f"scope boundary {key}")
layers = r.get("evidence_layers", {})
require(set(layers) == {"executable_model", "lean", "authored_rtl", "netlist", "place_and_route", "physical_hardware"}, "evidence layer separation")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate the evidence-layer assertions

When verify() is called with a supplied receipt, retaining these six keys while changing their values is accepted. For example, I changed physical_hardware to claim board validation and place_and_route to say it was not exercised, and the verifier still reported success. Because these values define what each evidence layer actually establishes, checking only the key set permits an internally contradictory or scope-inflated receipt; compare the complete expected mapping or validate every value.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3a8c0e5aac

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread SHA256SUMS Outdated
d6c7dd33771eb5386c9fc00e1003edce1d90b4a25625400eb8f0eccc57efc7e9 ./test/test_lsc1_fpga_packet_evidence.py
2dd4a7cbfcb2cf765e3068526fd1f68c5ab738d752ff6b60c0fa4260cab87219 ./test/test_lsc1_host_authored_rtl_boundary.py
e482475415e3a56c90db896fac31f7faff94a4a36f344fe6630222da88bcf07c ./test/test_lsc1_scalar_status_workflow.py
e0bd89e19ffae189a4a458fc9368a9f5eaa0ce7c44cfabf53a706d933e731178 ./test/test_lsc1_ulx3s_reproduction.py

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Refresh the checksum for the finalized regression test

The newly added test currently hashes to 16417a203b31e19b4c4d3c84a75a26c6ac271c15c1b48ceb13e016ab254296a1, not the recorded e0bd89e... value. Consequently tools/generate_checksums.py --check reports that SHA256SUMS is stale, and every standard make check (and therefore make package) fails when it reaches the checksum-check dependency.

Useful? React with 👍 / 👎.

@Th0rgal
Th0rgal merged commit 948265e into main Sep 7, 2026
87 of 89 checks passed
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