Skip to content

T087, phase 3's openDox root pin: code → dede32b4 (plan 034, T090 steps 1–2) - #18

Merged
brettheap merged 1 commit into
mainfrom
t087-phase3-root-pin-dede32b4
Oct 5, 2026
Merged

brettheap merged 1 commit into
mainfrom
t087-phase3-root-pin-dede32b4

Conversation

@brettheap

@brettheap brettheap commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Plan 034, task T087, the openDox root pin, phase 3. The plan is
specs/034-opendox-standalone-operation/tasks.md at opensoft/openxFactory main. This PR realizes box
9.5 (part) of the ratified add-neutral-product-standalone-operability, as T090 steps 1-2.

Arc: neutral-product-standalone-operability

  • Claim: openxFactory#656 comment 5992552627.
  • Landing word: the holder's lander merges; this writer does not.

What changes -- THE PIN THIS PR DELIVERS IS dede32b4b6f3d0f147d599776f83628c5af8ff3d

ONE commit (f451f68c, this PR's head), made by openRepoShape's scripts/bump-leg.py (the tool CONTRIBUTING.md names), moves exactly two things, as T062 (#16) did:

file before after
code (gitlink) 047bb4fa394f3e1bf42466062a67ef18e99f8d6a dede32b4b6f3d0f147d599776f83628c5af8ff3d
contracts/code-pin.yaml commit: 047bb4fa394f3e1bf42466062a67ef18e99f8d6a dede32b4b6f3d0f147d599776f83628c5af8ff3d
contracts/code-pin.yaml digests.tree_sha256 97536dbe7454ac062cc8fd3e34fd15a32eee52213f0292042b243f7e5c699a02 c2672463b4d8cf834026e2faae23478105d9e98650fcc07d971c19e387e7e0a7

Diffstat: 2 files changed, 3 insertions(+), 3 deletions(-). The spec leg and contracts/spec-pin.yaml are untouched.

No workflow file moves. No .github/workflows/*.yml references the code leg by @<sha>: bump-leg.py reported
"no @<sha> reference names this leg", and grep -rnE "openDox-code[^ ]*@[0-9a-f]{40}" .github finds nothing.

The commit pinned

dede32b4b6f3d0f147d599776f83628c5af8ff3d is the commit openDox-code#79's squash landed: T101's version bump to 0.1.0, the last phase-3 openDox-code
landing that changes the shipped package, right after openDox-code#78's release workflow. T099 publishes exactly the commit this root
pins (RULED 5963162921), and the release workflow's build job refuses a commit this root does not pin.
047bb4fa is an ancestor of dede32b4, so this is an ancestor move. Its first-parent history above the phase-2 pin is
22 landings (git log --first-parent 047bb4fa..dede32b4 in the code submodule):

commit landing
dede32b T099 release step: version 0.1.0 (plan 034) (openDox-code#79)
d59f3f2 T099, publish openDox to PyPI by trusted publishing (10.3's install line) (plan 034) (openDox-code#78)
651c35f T100 follow-on: the trust store's review findings (plan 034) (openDox-code#86)
32943cb T104, the console token travels in the opened URL, not /capabilities (plan 034) (openDox-code#84)
38d3350 T100, 16.3a: a served repository's bindings are trusted per machine (plan 034) (openDox-code#82)
ca9e1bd T082, 16.5: every other surface works with no model (plan 034) (openDox-code#76)
c4b55cc T102 follow-on: the chat rail reads a thread only with a branch session (plan 034) (openDox-code#85)
0116293 T102, the staging workbench offers the editors and the chat rail by scope (plan 034) (openDox-code#81)
390e2c2 T103, every loopback route checks the Host (DNS rebinding) (plan 034) (openDox-code#80)
e49b17c T084, 4.3: the last deferred reaches through declared seams; consumer_reach retired (plan 034) (openDox-code#77)
90ac703 T073, 13.4a — /capabilities gains an install block, read from the serving process's own settings (plan 034) (openDox-code#72)
8e37782 Broker-path credential hardening (follows T080): a minted token keeps a built-in credential's rules (plan 034) (openDox-code#64)
9197ccd T075, 10.2 and 10.2a — an installed entry point serves all 42 bundle files; intent-feed.js is not owed (plan 034) (openDox-code#73)
5e7ab00 T072, 13.1: the bundled PostgreSQL server, the local install's own child (plan 034) (openDox-code#69)
1130e99 T080, 16.3: the credential stays a reference, and a raw key is refused (plan 034) (openDox-code#63)
9a49040 T081, 16.4: "no model configured" is a state, shown before any turn (plan 034) (openDox-code#74)
2fc714d T079, 16.2: a model field the provider receives (plan 034) (openDox-code#62)
66ff725 T070, 13.4-13.6: OPENDOX_INSTALL_MODE and generate-and-open --local (plan 034) (openDox-code#67)
8a98e31 T078, 16.1: the OpenAI-compatible dialect joins DIALECTS (plan 034) (openDox-code#61)
7ff434d T071, 13.2 and 13.3: load_settings refuses a non-PostgreSQL DSN and a collapsed DSN pair (plan 034) (openDox-code#60)
d0d3cee T088, the lens's two seed actions are offered only where a binding answers them (R1Q19 (a)) (plan 034) (openDox-code#65)
2680eb5 T085, the standalone doxBench defaults for T027's seams, and T058's two workbench rules move into opendox.validator (plan 034) (openDox-code#71)

T087's After: line is T074, T077, T083, T084, T085, T088, T100, T101, T062 and T007 batch P. The openDox-code ones
are in the table above. T074, T077 and T083 are runs recorded in openxFactory (openxFactory#1224, openxFactory#1223 and openxFactory#1231). T062 landed as
openDox#16 -> d5098297. T007 batch P landed as openxFactory#1230. The chat rail's follow-on (openDox-code#85) and T100's
follow-on (openDox-code#86) are in the table too.

Falsifier

make pins at this PR's head (f451f68c):

$ make pins
  ok  spec: gitlink == contracts/spec-pin.yaml commit f7ee3c763b3a
  ok  spec: tree digest recomputes (e81f8530d93e…)
  ok  code: gitlink == contracts/code-pin.yaml commit dede32b4b6f3
  ok  code: tree digest recomputes (c2672463b4d8…)
  ok  contracts/shape-pin.yaml: 10 copied shape file(s) match their digests
pins ok

make validate (naming, manifest, lockstep pins; what CI runs) also passes, exit 0:

$ make validate
python3 scripts/validate-repository-naming.py --project project.yaml
  openDox                          neutral-product/assembly   also_matches project-leg/assembly
  openDox-spec                     project-leg/spec
  openDox-code                     project-leg/code
python3 scripts/validate-manifest.py
manifest ok: openDox (opendox), 3 legs
python3 scripts/validate-pins.py
  ok  spec: gitlink == contracts/spec-pin.yaml commit f7ee3c763b3a
  ok  spec: tree digest recomputes (e81f8530d93e…)
  ok  code: gitlink == contracts/code-pin.yaml commit dede32b4b6f3
  ok  code: tree digest recomputes (c2672463b4d8…)
  ok  contracts/shape-pin.yaml: 10 copied shape file(s) match their digests
pins ok

Each half-move is refused, measured in a copy of this tree:

  • the pin file moved and the gitlink not gives FINDING pin-gitlink-mismatch, exit 1;
  • the gitlink moved and the pin file not gives the same finding, exit 1;
  • an altered tree_sha256 gives FINDING pin-digest-mismatch, exit 1.

A fresh git clone of this branch with git submodule update --init --recursive, CI's own step, passes the three CI
steps (naming, manifest, pins), each with exit 0.

The digest, recomputed independently

c2672463b4d8cf834026e2faae23478105d9e98650fcc07d971c19e387e7e0a7 is sorted-ls-tree-r-v1 over dede32b4b6f3d0f147d599776f83628c5af8ff3d (329 records). Four methods gave the same value:

method result
A. standalone Python, NOT importing repo_shape, in the code submodule's own object store c2672463...e0a7, 329 records
B. shell only: git ls-tree -r -z <sha> | tr '\0' '\n' | sed '/^$/d' | LC_ALL=C sort | sha256sum the same
C. bump-leg.py, which uses repo_shape.tree_digest, and validate-pins.py's recompute the same
D. the forge's data: gh api repos/opensoft/openDox-code/git/trees/<sha>?recursive=1 (not truncated), tree rows dropped, mode type sha TAB path sorted and hashed the same, 329 records

Sanity check first. Method A reproduced the trusted value for 047bb4fa, 97536dbe7454ac062cc8fd3e34fd15a32eee52213f0292042b243f7e5c699a02 (299 records),
before it was applied to dede32b4.

Not this PR

  • contracts/CHANGELOG.md is not edited. A code-pin move carries no CHANGELOG line (T062's reason: the code leg
    carries no contract bytes).
  • No bundle is cut and no tag moves. T099 publishes the PyPI release from this pin; that is T099's.
  • The spec leg, contracts/spec-pin.yaml, contracts/manifest.yaml and every workflow file are untouched.
  • The consumer side is not this PR's. T086 (openXdox-code#37) moves its opendox @ pin to this same openDox-code
    commit. T094 (T090 steps 5-6) then moves the openXdox root, and openxFactory's pin pairs and host wiring with it.

Lane: openxfactory-4 (openXfactory-4-openDox_extraction)

🤖 Generated with Claude Code

Summary by Sourcery

Enhancements:

  • Advance the openDox code leg pin to the phase-3 release commit and synchronize its recorded tree digest.

…anded; plan 034)

Move the `code` gitlink and `contracts/code-pin.yaml` (`commit:` and
`digests.tree_sha256`) to dede32b4, the commit openDox-code#79's squash landed
(T101's version bump to 0.1.0), which carries every phase-3 openDox-code
landing (22 on the first-parent line above 047bb4fa). T099 publishes
exactly the commit this root pins (RULED 5963162921).

Made by openRepoShape's scripts/bump-leg.py: tree c2672463b4d8cf834026e2faae23478105d9e98650fcc07d971c19e387e7e0a7.
No `.github/workflows/*.yml` references the code leg by `@<sha>`, so none
moves.

Falsifier: `make pins` in the openDox root -- pins ok.

Arc: neutral-product-standalone-operability
Lane: openxfactory-4 (openXfactory-4-openDox_extraction)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 5, 2026 11:52
@sourcery-ai

sourcery-ai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

This PR performs the phase-3 openDox root pin update by moving the code gitlink and matching contract commit from 047bb4fa to dede32b4, and replacing the code tree digest with the digest verified for that commit. The spec leg and repository wiring remain untouched; the supplied validation confirms lockstep pin and digest integrity.

Flow diagram for the lockstep openDox code pin update

flowchart LR
    A[code gitlink: 047bb4fa to dede32b4] --> C[make pins]
    B[contracts/code-pin.yaml commit and tree_sha256 updated] --> C
    C --> D[validate-pins.py]
    D --> E[code pin and digest verified]
    F[spec leg unchanged] -.-> E
Loading

File-Level Changes

Change Details Files
Advance the openDox code leg to the phase-3 release commit and keep the root’s gitlink and contract pin synchronized.
  • Move the code submodule gitlink from 047bb4fa to dede32b4.
  • Update the contract’s pinned commit to the same release commit.
  • Leave the spec leg, manifest, workflows, and consumer-side pins unchanged.
code
contracts/code-pin.yaml
Replace the verified code-leg tree digest for the new commit.
  • Update tree_sha256 to the independently recomputed digest for dede32b4.
  • Preserve the existing sorted-ls-tree-r-v1 digest definition and validation wiring.
contracts/code-pin.yaml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sonarqubecloud

sonarqubecloud Bot commented Oct 5, 2026

Copy link
Copy Markdown

Copilot AI 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.

Copilot review overview

🟢 Approval recommended

The gitlink and pin metadata are synchronized, and the lockstep validation completed successfully.

Review effort: Balanced
Findings: None

What changed in this PR

Advances the openDox code leg to the phase-3 release commit while preserving pin integrity.

Changes:

  • Updates the code gitlink to dede32b4.
  • Updates the matching commit and verified tree digest.
File Description
code Advances the code-leg gitlink.
contracts/​code-pin.yaml Records the matching commit and tree digest.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@brettheap
brettheap marked this pull request as ready for review October 5, 2026 11:55
@brettheap

Copy link
Copy Markdown
Contributor Author

READY at f451f68 — Lane: openxfactory-4 (openXfactory-4-openDox_extraction)

Holder: T087, phase 3's openDox root pin (T090 steps 1–2). It is an arc landing, with Claim 5992552627.

  • The move. ONE commit, made by bump-leg: the code gitlink and contracts/code-pin.yaml move to openDox-code dede32b4.
    • That commit is #79's squash, the 0.1.0 bump. It contains #78 d59f3f26, the release workflow, and every phase-3 landing.
    • It is an ancestor move from 047bb4fa.
    • No workflow @<sha> names the code leg.
  • The digest. c2672463…e7e0a7, 329 records. Four methods agree.
  • Gates.
    • make validate and make pins pass.
    • The half-move falsifier refuses each case: pin-gitlink-mismatch, and pin-digest-mismatch.
    • The fresh-clone CI steps pass.
    • CI validate and SonarCloud are green.
    • Copilot: "Approval recommended", with no findings.
  • What follows. T099 publishes exactly this pinned commit, from the tag v0.1.0. Once this lands:
    • T086 (openXdox-code#37) moves its pin to dede32b4;
    • T076 (openDox#17) merges root main;
    • lane openXfactory-3's ahead golden PR opens.

@sourcery-ai sourcery-ai 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.

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Approved.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

@brettheap
brettheap merged commit e1e3a3c into main Oct 5, 2026
4 checks passed
@brettheap

Copy link
Copy Markdown
Contributor Author

Lane: openxfactory-4 (openXfactory-4-openDox_extraction)

LANDED — lane openxfactory-4, 2026-10-05T11:58:38Z, PR #18 → e1e3a3c (opensoft/openDox main; plain gate)

Brett: land phase 1 / phase 2 PRs when green

brettheap added a commit to opensoft/openXdox that referenced this pull request Oct 5, 2026
… (plan 034 T094, T090 step 5) (#22)

Lane: openxfactory-4 (openXfactory-4-openDox_extraction)

Plan 034, task **T094**, step 5 of **T090**'s pin procedure: *"The openXdox root moves its `code` gitlink and `code-pin.yaml`, and moves `contracts/opendox-pin.yaml` to step 2's root commit."* The plan is `specs/034-opendox-standalone-operation/tasks.md` at opensoft/openxFactory `main`. Precedent: #21 (T064), which landed as `f257e021` and was followed by opensoft/openxFactory#1215.

- **Claim:** opensoft/openxFactory#656 (comment) (it covers T087 and T094).
- **Landing word:** the holder's lander merges; this writer does not.

T094's openxFactory half is a separate PR. It re-points openxFactory's `openXdox` gitlink to this PR's LANDED sha, and moves its `openDox` pair to `e1e3a3c3` in the same commit, with phase 3's host wiring.

## The lockstep

| site | before | after |
| --- | --- | --- |
| `code` gitlink | `6a3b93b9` | **`56e1c238`** |
| `contracts/code-pin.yaml` `commit:` (line 24) | `6a3b93b93cd6…` | **`56e1c238681a7693a4d8d42a62c1523cf4d4ab91`** |
| `contracts/code-pin.yaml` `digests.tree_sha256` (line 39) | `4ef2b4f7…aeb3` | **`f4bddb506119132441637be32bc801c8ad4f95b8157a692c0a4567224c693ce3`** |
| `contracts/opendox-pin.yaml` `commit:` (line 34) | `d5098297…` | **`e1e3a3c3f8dd38214510412b71a2e858c6179532`** |
| `contracts/opendox-pin.yaml` `digests.tree_sha256` (line 40) | `2815ca23…57cc` | **`55a110f49d268e22d382d47d778dfaf9298c93b555e3c4fcb621afc99f9d011b`** |

No `.github/workflows/*.yml` names the code leg by `@<sha>` (`grep -rnE "openXdox-code[^ ]*@[0-9a-f]{40}" .github` finds nothing), so the README's third site does not exist here.

**Each gitlink and its pin file move in one commit.** `2fa15af5` moves `code` with `code-pin.yaml` (openRepoShape's `scripts/bump-leg.py`), and moves `contracts/opendox-pin.yaml`. `make pins` passes there. `db6cc2a4` changes prose only: the opendox-pin file's comments, `contracts/manifest.yaml` and `contracts/CHANGELOG.md`.

**Both moves are ancestor moves.** `6a3b93b9` is an ancestor of `56e1c238`, and `d5098297` is an ancestor of `e1e3a3c3` (`git merge-base --is-ancestor`, both exit 0). `56e1c238` is openXdox-code `main`, and `e1e3a3c3` is openDox `main`'s parent: openDox#17 (T076, the root README only) landed after it as `504324de`.

**What the code leg's advance carries.** `6a3b93b9..56e1c238` is one first-parent commit, a squash landing of plan 034's phase 3 that carries the `Arc:` trailer:

- `56e1c23`: T086, openXdox contributes its columns: the governed gate, scope, kickoff and register at openDox's seams, the two route columns through the facet, the direction at (0, 0) (plan 034) (opensoft/openXdox-code#37)

Its `pyproject.toml` pins `opendox @ git+https://github.com/opensoft/openDox-code@dede32b4…`, the openDox-code commit openDox's root pins at `e1e3a3c3`.

**What the openDox pin's advance carries.** `d5098297..e1e3a3c3` is one commit:

- `e1e3a3c`: T087, phase 3's openDox root pin: code → dede32b4 (plan 034, T090 steps 1–2) (opensoft/openDox#18)

It moves `code` `047bb4fa` → `dede32b4` with `contracts/code-pin.yaml`, and changes no other path. So openDox's `contracts/manifest.yaml`, its `spec` gitlink and `contracts/spec-pin.yaml` are byte-unchanged, and the openDox bundle this one composes over is still `dox-v1.1`.

## The digests, three ways

| tree | records | `scripts/repo_shape.py` `tree_digest` | independent `ls-tree` + `sha256` | `repo_shape.tree_digest_from_gh` (the forge's tree) |
| --- | ---: | --- | --- | --- |
| openXdox-code `56e1c238` | 191 | `f4bddb50…3ce3` | `f4bddb50…3ce3` | `f4bddb50…3ce3` |
| openDox `e1e3a3c3` | 28 | `55a110f4…011b` | `55a110f4…011b` | `55a110f4…011b` |

Controls: the same three methods recompute the recorded `4ef2b4f7…aeb3` at `6a3b93b9` (187 records) and `2815ca23…57cc` at `d5098297` (28 records).

## `contracts/opendox-pin.yaml`, edited in place

It stays at 164 lines, with every line in its position. Lines 34, 40, 55, 56, 57, 58, 143 change:

- line 34, `commit:`;
- line 40, `tree_sha256`;
- lines 55-58, the per-file paragraph. It was checked at `dc7aa08f`, `663ac683` and `d5098297`, and is unchanged at `e1e3a3c3`: `dox-v1.1` and FOUR `entries:`, all at openDox-spec `f7ee3c76`;
- line 143, the migration triple's `runbook`, which names "the pinned code leg". That is `dede32b4` now.

**The migration triple.** No migration path changes over openDox-code `047bb4fa..dede32b4`, and `migrations/` holds the same two files. So `range: "0001..0002"` and `reversible: false` stay, and only `runbook`'s leg changes. openxFactory's own `contracts/opendox-pin.yaml` takes the identical block in T094's openxFactory PR. `tests/opendox_pin/test_opendox_pin_verifier.py` asserts the two blocks are equal.

## Prose kept true in the same PR

- **`contracts/manifest.yaml`.**
  - "THE CODE LEG CONTRIBUTES NO ENTRY" now covers `56e1c238`. The leg's packaged copies under `src/openxdox/contracts/` are unchanged from `6a3b93b9` (`git diff --quiet 6a3b93b9 56e1c238 -- src/openxdox/contracts contracts` exits 0), so none of the five rows moves.
  - "WHAT THIS BUNDLE DEPENDS ON" names `e1e3a3c3` and opensoft/openDox#18, and keeps #21's advance as history.
  - The tag paragraph adds `d5098297` from #21 and `e1e3a3c3` from this commit forward.
  - The lockstep paragraph's openxFactory reading is `f257e021`, whose blob names `d5098297`.
- **`contracts/CHANGELOG.md`, `## Unreleased`.** It records the code leg's sixth advance and the openDox pin's advance. Its closing sentence is true as written: both legs' `main` are exactly the commits this root pins.
- **No tag moves.** `xdox-v1.0` stays where it is. No advance cuts a bundle.

## Validators, as `validate.yml` runs them (at `db6cc2a4`)

| check | result |
| --- | --- |
| `python3 scripts/validate-repository-naming.py --project project.yaml` | exit 0 |
| `python3 scripts/validate-manifest.py` | exit 0: `manifest ok: openXdox (openxdox), 3 legs` |
| `make pins` (`python3 scripts/validate-pins.py`) | exit 0: `ok  spec: gitlink == contracts/spec-pin.yaml commit f088b09732e2`, `ok  spec: tree digest recomputes (b7dbd5456a1a…)`, `ok  code: gitlink == contracts/code-pin.yaml commit 56e1c238681a`, `ok  code: tree digest recomputes (f4bddb506119…)`, `ok  contracts/shape-pin.yaml: 10 copied shape file(s) match their digests`, `ok  openDox: pin commit e1e3a3c3f8dd digest recomputes (gh-api-tree-recursive)`, `pins ok` |
| `make validate` | exit 0 |

`make pins` passes at `2fa15af5` too.

## Falsifier

`make pins` is step 5's falsifier. Each half-move is refused, measured in a scratch clone of this branch:

| case | `validate-pins.py` |
| --- | --- |
| this head, then the lockstep commit `2fa15af5` alone | `pins ok`, exit 0, both |
| the `code` gitlink back at `6a3b93b9`, the pin files at this head | `FINDING pin-gitlink-mismatch`, exit 1 |
| the gitlink at `56e1c238`, `contracts/code-pin.yaml` back at `main`'s | `FINDING pin-gitlink-mismatch`, exit 1 |
| one hex digit of `code-pin.yaml`'s `tree_sha256` altered | `FINDING pin-digest-mismatch`, exit 1 |
| one hex digit of `opendox-pin.yaml`'s `tree_sha256` altered | `FINDING neutral-pin-digest-mismatch`, exit 1 |
| restored | `pins ok`, exit 0 |

A fresh clone of this branch from GitHub, with `git submodule update --init --recursive` (CI's own step), passes CI's three steps (naming, manifest, pins), each with exit 0.

No check here reads openDox's `main` tip: `validate-pins.py` recomputes the pinned commit's digest from the forge's tree, so `e1e3a3c3` verifies although openDox#17 (T076, the root README) has since landed as `504324de`. Step 5 pins step 2's root commit, as T090's text says.

## What this does to openxFactory

`verify-opendox-pin.py` check 5 reads this root's `contracts/opendox-pin.yaml` as a blob, at whatever commit openxFactory's `openXdox` gitlink names. This PR changes that file's `commit:` to `e1e3a3c3`. So when openxFactory's `openXdox` gitlink moves here, its own `openDox` pair must move to `e1e3a3c3` in the SAME commit (measured: with the openDox pair alone moved, `verify-opendox-pin.py` refuses `opendox-pin-lockstep-mismatch`). T094's openxFactory PR does exactly that. Until it lands, openxFactory keeps reading `f257e021`.

Measured before this PR, in an openxFactory staging clone with both pairs moved in ONE commit, over a rehearsal of these two commits whose code leg was opensoft/openXdox-code#37's last pre-squash head `69997db7`: `verify-opendox-pin.py` and `verify-openxdox-pin.py` both print OK, and openxFactory's composition, host-wiring, carve-mapping and pin suites pass (410 passed). `56e1c238` differs from `69997db7` in three files: `pyproject.toml`'s `opendox` pin (`c4b55cc4` → `dede32b4`), `tests/test_doxchat_model_intake.py` and `.github/workflows/validate.yml`. T094's openxFactory PR measures again at this PR's LANDED sha.

## Landing (forced order)

1. ~~T087, opensoft/openDox#18, lands.~~ Landed → `e1e3a3c3`.
2. ~~T086, opensoft/openXdox-code#37, lands.~~ Landed → `56e1c238`.
3. This PR lands. Squash or merge, never rebase, and the landing carries the `Arc:` line.
4. Lane openXfactory-3's ahead PR (the CLI help golden, the usage line and the rebound-Host case) lands in opensoft/openxFactory.
5. T094's openxFactory PR moves BOTH pin pairs in one commit, to this PR's LANDED sha and to `e1e3a3c3`, records the landed tree's digest, and carries phase 3's host wiring.

Plain gate: this repository has no `openspec/changes/`, so there is no Rule 6 window. **This PR is not merged by the actor that opened it.**

Arc: neutral-product-standalone-operability

🤖 Generated with [Claude Code](https://claude.com/claude-code)


Arc: neutral-product-standalone-operability
Lane: openxfactory-4 (openXfactory-4-openDox_extraction)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
brettheap added a commit to opensoft/openxFactory that referenced this pull request Oct 5, 2026
…Host case hold at both pins (T066's form; not an arc landing) (plan 034) (#1234)

Lane: openxfactory-4 (openXfactory-4-openDox_extraction)
Authored by lane openXfactory-3, delegated by lane openxfactory-4 (#656 5984809313)

Plan 034, **T094's ahead PR** (`specs/034-opendox-standalone-operation/tasks.md` at openxFactory `main` `ba6bb870`, T094's **After** line: *"the ahead PR (E1 (a), a non-arc PR with no task of its own: the golden, the usage line and the rebound-Host case)"*). The rulings are E1 (a) and E3 (a), recorded with `5970369724`; the tree at 32, `5970917267`; and E3 (a)'s reading, E5 (a) and the rebound-Host case, `5972924576`. This PR makes three openxFactory test surfaces hold at BOTH openDox legs:

- **the current pins**: openDox `d5098297` (code `047bb4fa`) and openXdox `f257e021` (code `6a3b93b9`);
- **phase 3's leg**: openDox-code `dede32b4`, the commit that T087's openDox root `e1e3a3c3` (opensoft/openDox#18) pins.

**Not an arc landing.** Per T091 and plan.md § "The trailer, the guard and Rule 6", no commit of this PR and no line of this body carries the arc trailer. It touches no `openspec/` path, so no Rule 6 window applies. No commit and no line here carries a closing keyword. It moves no pin and carries no host wiring (E3 (a)): T094 moves both pin pairs.

The three commits were prepared by lane openxfactory-4 in its T094 prep and are carried onto `main` unchanged (the same patch ids). Their "Measured:" paragraphs are that prep's runs; this body's are below. `1661c63d` merges `main`'s one later commit (T007 batch P, #1230), which touches none of these files.

## What it changes

| file | change | both-pins form |
| --- | --- | --- |
| `tests/domain_profile/fixtures/cli-help-tree.phase3.golden.txt` (new) | The assembled `--help` tree at phase 3's leg, 32 sections: T070's `generate-and-open --local`; T079's and T080's `--model`, the `none` auth kind and the optional credential reference on `model-binding add` and `edit`; T084's program name `opendox` in every usage line, with openDox's own root description and epilog; and T100's `model-binding trust`, the 32nd entry point (research R8). It lives outside `tests/ideation-dashboard/`, a `moved_paths:` prefix of the carve manifest, where a new file is `carve-file-undeclared`. | Read only where the pinned parser has phase 3's layout. |
| `tests/ideation-dashboard/test_extension_point_parity.py` | `pinned_help_golden` picks the golden off the pinned parser, never off the text compared: its `prog` (`ideation-dashboard` before T084, `opendox` from it) and whether `model-binding` offers `trust` (T100). A leg with one change and not the other is refused by name. Two new cases: the two goldens hold the same entry points plus `model-binding trust`, and the selector's negative control. | Both layouts, each held byte for byte. |
| `tests/ideation-dashboard/test_cli_column_split.py` | `test_a_contributed_verb_is_reachable_in_both_documented_invocations` reads the usage line's program off the pinned leg, `cli.PROG` (T084), and `ideation-dashboard` where the leg has no `PROG` (E5 (a)). | Both program names. |
| `tests/ideation-dashboard/test_doxbench_routes.py` | `test_console_gate_refuses_host_not_naming_the_bound_port` expects `403 invalid_host`, from `serve.FOREIGN_HOST_*`, where the leg has T103's Host gate (openDox-code#80), and `console_required` where it does not. Either way the request is refused and the model port is never asked. | Read off the leg (`serve.FOREIGN_HOST_ERROR`), never off the answer. |

None of the four files is one of F11.1's declared surfaces (`HOST`, `HOST_TESTS`, `PIN_PAIRS`, `COMPOSITION_TESTS`, `ADMITTED_ARC_EDITS`), which is why they move here and not in T094's arc landing.

## The golden, regenerated from T087's commit

The tree is the parity test's own walk (`walk_parser` and `help_tree`, at `COLUMNS=100`), printed by a probe that makes the suite's two set-up calls (`carved_reach.install(tests=True)`, `register_openxfactory()`) with the openDox code leg at the named commit:

| openDox-code leg | sections | bytes | sha256 | against this PR's golden |
| --- | ---: | ---: | --- | --- |
| `047bb4fa`, the current pin (the control) | 31 | 53425 | `9cbeca99…` | byte for byte `tests/ideation-dashboard/fixtures/cli-help-tree.golden.txt`, the golden `main` already holds |
| **`dede32b4`, T087's** (root `e1e3a3c3`) | 32 | 52827 | `9cc6e383…` | **identical** |
| `38d3350e` with #84 `af2a2efb` and #86 `96ae8816` merged (the drift check before they landed) | 32 | 52827 | `9cc6e383…` | identical |

- openDox-code#79's `0.1.0` changes `pyproject.toml` only. The parser has no version flag and the tree carries no version string.
- The openXdox leg does not move the tree: the same bytes come out with openXdox-code at its pin `6a3b93b9` and at T086's head (openXdox-code#37, `69997db7`).

## The measurements

Every local run follows `pytest-suite`'s own steps: a checkout named `openxFactory` with `openXwallet`, and `openDox` and `openXdox` recursively, initialized; Python 3.12.3; the hash-pinned lock; node 24; the pinned OpenSpec CLI 1.12.0; `PINNED_CORE_CHECKOUT` at codexFactory `b21f0100`; then `python3 -m pytest tests/ -q -m "not postgres"`.

| run | head | legs | result |
| --- | --- | --- | --- |
| **CI** | `1661c63d` | the pins | All 14 check-runs at the head succeeded. `pytest-suite` (run `37311052114`): **8929 passed, 6 skipped, 0 failed**: `selected=9347 passed=9341 skipped=6 failures=0 errors=0`, margin 2297, `skipped==6`; the freshness verifier and the vector replay passed. |
| P | `1661c63d` | the pins | The parity, doxbench-routes, CLI column split and carve test mapping suites: **324 passed**. `validate-carve-manifest`: OK, 456 rows, none undeclared. Full suite **8930 passed, 5 skipped, 0 failed**: `selected=9347 passed=9342 skipped=5 failures=0 errors=0`; the freshness verifier and the vector replay passed. |
| P0 | `7657cc3e`, before the merge of `main` | the pins | the same four suites, 324 passed; `validate-carve-manifest` OK; full suite **8930 passed, 5 skipped, 0 failed**: `selected=9347 passed=9342 skipped=5 failures=0 errors=0`, the freshness verifier and the vector replay passed |
| X3 | this PR's files, openDox code at `dede32b4` and openXdox code at T086's head `69997db7`, overlaid with no pin moved | phase 3 | The parity file, the rebound-Host case and the usage-line case: **14 passed, 2 failed**. The two are T094's own composition cases (next list). |
| X2 | the same, with openXdox code at its pin `6a3b93b9` | mixed | 13 passed, 3 failed: the same two, and the rebound-Host case refused at server build (`RouteBindingError`: no `_serve_index`, no `_handle_gate_action`), because phase 3's openDox leg no longer carries `consumer_reach` for phase 2's openXdox leg. No phase pins this mix; T094 moves both pairs together. |

- **The two reds at phase 3 are T094's.** `test_the_core_dispatch_table_is_unchanged[_route-pinned0]` (the `/capabilities` arm reaches `_serve_bytes`, `_session_repository` and `install_report` from T103) and `test_the_mixins_precede_simplehttprequesthandler_in_the_mro` (`consumer_reach` is gone). Both are named composition tests under R1Q2 (a), and T094's arc landing updates them.
- **Why a local run skips 5, not CI's 6.** The work tree sits inside an xFactory aggregation checkout, so `tests/domain_profile/test_session_worktree_book_scan.py::test_worktree_container_is_gitignored_in_the_aggregation_repo` finds the aggregation, runs and passes, where a runner skips it. CI's 8929 passed + 6 skipped and P's 8930 passed + 5 skipped are the same 8935 tests. The local five are the two `tests/notebooklm` module skips, the two conformance-gate self-gate skips and the LedgerxFactory fixture-drift guard.

## Review

| Copilot at | verdict | threads | answered in |
| --- | --- | --- | --- |
| `1661c63d` | Approval recommended; findings: none | none | nothing to answer |

## Landing

- No arc trailer, no closing keyword, no `openspec/` path, so there is no Rule 6 window.
- It opens as a DRAFT. With its gates and Copilot clean at its head it leaves draft and READY-CANDIDATE is posted on #656; the holder marks it READY, and the landers merge it.
- It lands **before T094**, whose **After** line names it. T094 then moves both pin pairs, with the host wiring and its composition tests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)


Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
brettheap added a commit to opensoft/openxFactory that referenced this pull request Oct 5, 2026
…, with phase 3's host wiring: openXdox's columns and the governed binding-trust policy (plan 034) (#1236)

Lane: openxfactory-4 (openXfactory-4-openDox_extraction)

Plan 034, task **T094**: phase 3's consumer pins (T090 step 6) with phase 3's host wiring, `specs/034-opendox-standalone-operation/tasks.md` at openxFactory `main`. The precedents are T047 (opensoft/openXdox#20, then #1181) and T064 (opensoft/openXdox#21, then #1215).

- **Claim:** #656 (comment) (it covers T087 and T094).
- **Landing order, done:**
  - T087: opensoft/openDox#18 → `e1e3a3c3` (openDox-code `dede32b4`, the 0.1.0 commit T099 publishes).
  - T086: opensoft/openXdox-code#37 → `56e1c238`.
  - T090 step 5: opensoft/openXdox#22 → `9564d5d9`.
  - Lane openXfactory-3's ahead PR (D2, non-arc: the CLI help golden, the usage line and the rebound-Host case at both pins) → #1234, `ca1c148646f1111bc8049bc9cceb3c14ef276967`. This branch merges `main` in at `9cd1bf23` (a merge, never a rebase).
- **Holder decisions in force (2026-10-05):**
  - (a) both pin pairs move in ONE commit, as in T047 and T064 (below);
  - (b) T092's phase-3 `edits[].note` annotations ride in T089's checkpoint PR (lane openXfactory-3's D3; #656 comment `5987195870`, D5), NOT here. This PR touches no manifest note;
  - (c) the stale `src/opendox/consumer_reach.py` admission is removed and asserted ABSENT;
  - (d) the 4 + 3 carve-time files the walk still names stay as T064 left them;
  - (e) the merge of `main` (`9cd1bf23`) carries the `Lane:` line and no `Arc:` line. T091's trailer belongs on realization commits and on the landing, and the squash landing writes `Arc:` from this body. On the merge, F11.1's guard would charge #1234's non-arc files to the arc.
- It stays a DRAFT until the holder marks it READY.

## The pins: both pairs in ONE commit (`caa8d377`)

| pair | gitlink | pin file `commit:` | `digests.tree_sha256` |
| --- | --- | --- | --- |
| openDox | `d5098297` → **`e1e3a3c3`** | same (`contracts/opendox-pin.yaml`:118) | `2815ca23…57cc` → **`55a110f49d268e22d382d47d778dfaf9298c93b555e3c4fcb621afc99f9d011b`** (28 records) |
| openXdox | `f257e021` → **`9564d5d9`** | same (`contracts/openxdox-pin.yaml`:109) | `52f0598e…6959` → **`11585eadf4fef2ffcb4419194fa6a52444f56759cfc427d41c352a6b8803cbd2`** (29 records) |

- **`e1e3a3c3` is opensoft/openDox#18's squash (T087), one commit above `d5098297`.** It moves `code` `047bb4fa` → `dede32b4` with `contracts/code-pin.yaml` and changes no other path, so openDox's `contracts/manifest.yaml`, its `spec` gitlink and the bundle (`dox-v1.1`) are unchanged. openDox's `main` has since moved to `504324de` (opensoft/openDox#17, T076, the root README only). Step 2's root commit is the one T090 pins, and no check reads `main`'s tip.
- **`9564d5d9` is opensoft/openXdox `main`, where #22 squash-landed** (its tree equals #22's head `db6cc2a4`). It moves `code` `6a3b93b9` → `56e1c238`, which is openXdox-code `main` after #37 (T086), and `contracts/opendox-pin.yaml` `d5098297` → `e1e3a3c3` (T090 step 5).
- Every digest was recomputed three ways: `repo_shape.tree_digest`, an independent `ls-tree` + `sha256`, and the forge's tree listing (`repo_shape.tree_digest_from_gh`). Controls: the same three methods reproduce the recorded `52f0598e…6959` at `f257e021` and `2815ca23…57cc` at `d5098297`.
- **Why one commit and not "one commit each" (T090 step 6).** #22 changes the openDox pin that `verify-opendox-pin.py` check 5 reads through the openXdox gitlink, and `docs/openxdox-pin-resync-runbook.md` § 4 prints DIFFERENT. Each split order was measured on this branch's base, and `verify-opendox-pin.py` exits 2 in both:
  - the openDox pair alone: `REFUSE opendox-pin-lockstep-mismatch: this pin names openDox@e1e3a3c3f8dd38214510412b71a2e858c6179532, but openXdox's own openXdox/contracts/opendox-pin.yaml names openDox@d5098297a5c262f9977193305210bccb4ec51e89; two direct declarations of one product's bytes disagree.`
  - the openXdox pair alone: `REFUSE opendox-pin-lockstep-mismatch: this pin names openDox@d5098297a5c262f9977193305210bccb4ec51e89, but openXdox's own openXdox/contracts/opendox-pin.yaml names openDox@e1e3a3c3f8dd38214510412b71a2e858c6179532; two direct declarations of one product's bytes disagree.`

  So "one commit each" cannot be met without an intermediate red commit. **The holder ruled the single commit for phase 3 on 2026-10-05**, as for phase 1 (T047, #1181) and phase 2 (T064, #1215, decided 2026-09-28). This PR therefore departs from T090 step 6's "one commit each" for the third time. Each pair still moves as one unit (box 9.5).
- Both pin files are edited in place, keeping their line counts (216 and 154). The openDox `migration:` block keeps `range` (`0001..0002`) and `reversible` (`false`): no migration path changes over openDox-code `047bb4fa..dede32b4`. Its `runbook` names the new code leg `dede32b4`, and the block is identical to openXdox's derived copy at `9564d5d9`, which `tests/opendox_pin` asserts.
- **Gates.**
  - `verify-opendox-pin.py`: `OK opendox-pin verified: openDox@e1e3a3c3f8dd38214510412b71a2e858c6179532, gitlink read from HEAD, sorted-ls-tree-r-v1 tree digest recomputed (55a110f4…011b), lockstep with openXdox confirmed`.
  - `verify-openxdox-pin.py`: `OK openxdox-pin verified: openXdox@9564d5d9462ffd1a3155d9177206368e5061efa8, gitlink read from HEAD, sorted-ls-tree-r-v1 tree digest recomputed (11585ead…cbd2)`.

## What else it carries

| commit | what | F11.1 surface |
| --- | --- | --- |
| `3c1c1146` | **The host wiring.** `scripts/opendox_host.register_openxfactory()` calls `openxdox.column_contributions.register()` (T086) after the projection line, and refuses by name when it registers nothing. **`GovernedBindingTrust`** (RULED #656 `5970369724`, "Governance approval (Recommended)") is the sixth `seams()` entry, before the home seam, with its take-back row. Its verdicts: a binding pending in the governed declarations is untrusted (host basis, the governed reason); an unreadable declarations document admits nothing; otherwise trusted, host basis. It answers the console intake's own question, `intake_verdict`, as plan 034's T100 entry says a host policy must. Its `record()` writes nothing and returns None, which openDox-code#86 reads as "no record" (`doxbench_trust.recording_for`; #656 `5986391296`, applied to T094 by `5988088910`), so a failed `add` or `edit` write is refused as the write's own failure and never with `REASON_NO_WITHDRAWAL`. `tests/domain_profile/test_host_registers_binding_trust.py` (new, 9 tests, 11 cases at `7e31eca1`) and `test_openxfactory_host_wiring.py` (six seams; the three columns the facet composes; each declared once) cover it. They pin openDox-code#86's final `REMEDY_NOT_BY_TRUST` and `INTAKE_HOST_NOT_ADMITTED` strings. Planted mutants, measured over the draft rounds of this same code, are each killed: M1-M3 and M5 by `test_host_registers_binding_trust.py`, the column line removed (M4) by `test_doxbench_routes`, `intake_verdict` removed or admitting everything (M6, M7), and `record()` returning the verdict, returning True, or writing MachineTrust's store (M8, M9, M11). | HOST, HOST_TESTS |
| `3c1c1146` | **Composition tests**, amended in the arc: `test_extension_point_parity.py` (the `/capabilities` arm of T073 and T103, and the MRO's T084 layout), `test_serve_column_split.py` (the snapshot arm's four handlers are the core's own after T086's trim; every column method is the column's own), and `test_doxbench_status_exemption.py` (T085's `register_default_status_exemption` joins the readers of the registered rail). | COMPOSITION_TESTS |
| `1c5f8edb` | The render lane's `RENDER_LEG_MODULES` and the seal test's `RENDER_UNIT_IMPORTS` gain `opendox/doxbench_trust.py`, `opendox/doxbench_intake.py` and `openxdox/column_contributions.py`, which the host bootstrap now imports. The seal carries a leg's whole `src/`, so no sealed artifact changes. `scripts/profile_openxfactory.py`'s note on the two openXdox columns moves to the past tense. | ADMITTED_ARC_EDITS (both paths); HOST |
| `24215223` | `test_ruling_q7_two_direct_upstreams_in_lockstep`'s snapshot literal moves `d5098297` → `e1e3a3c3`, as its comment says it does on every bump. | ADMITTED_ARC_EDITS |
| `eda75977` | **The lane route's predicate check** (T086's Q8 (a)). openXdox-code's `test_the_hosted_session_arrival_path_is_recorded_and_not_built` no longer reads openxFactory's `_handle_refresh_action` (opensoft/openXdox-code#37 narrowed its loop to the leg's own routes), so `tests/domain_profile/test_lane_route_asks_the_hosted_ref_predicate.py` (new, 2 tests) asserts it here: the route's body calls `hosted_ref_refused(` (openXdox's predicate), and on a hosted plane a refresh naming a session ref is refused with `session_unavailable` before it runs, while a ref-less one runs. Three planted mutants are each killed: the check removed, the call kept but not deciding, and the call asked as loopback. | HOST_TESTS |
| `b3a4b6e0` | **29 `created:` admissions** in `docs/opendox-carve-admissions.yaml`, pinned in `tests/carve_arrival` by path, `since` and count, as T047's 37 and T064's 129 are, **and one removed** (below). | ADMITTED_ARC_EDITS (both paths) |
| `16136990` | The admissions test's ordinal paragraph and its sixteenth-bump docstring and comment name this PR, #1236 (a follow-up commit: the number did not exist before the PR). | ADMITTED_ARC_EDITS |
| `9cd1bf23` | Merge of `main` at `ca1c1486` (lane openXfactory-3's ahead PR). It merged with no conflict, and its four files are byte-identical to the ahead commits this branch was measured over. It is not a realization commit, so it carries the `Lane:` line and no `Arc:` line (T091): F11.1's guard selects commits by that line, and walked over this branch it would otherwise charge #1234's two non-arc files to the arc. | (not on `main`'s first-parent line) |
| `7e31eca1` | **Copilot's finding at `16136990`, and the pre-review's six fix-now findings.** (Copilot) A refusal now gives back the unread defaults this call replaced: `_DEFAULTS` names the two globals and the default-registration call of each default-holding seam (T085's doxBench pair, T100's trust default). A write that replaced an unread default is recorded with it, and the take-back registers it again as the unread default, as `openxdox.column_contributions` does. The pre-review's six: (1) the no-columns refusal is tested, and no host seam is written; (2) a refusal at the trust seam is tested on fakes and on the pinned leg; (3) "five seams" becomes six where the count is meant; (4) `GovernedBindingTrust`'s docstring names the one case that changed; (5) the failed-write case skips as root; (6) `__all__` is in ASCII order and names `GOVERNED_PENDING_REASON`. The give-back case, the six-seam message and the exports case each failed before the fix. Planted mutants M12-M19 are each killed. | HOST, HOST_TESTS |

The 29 admissions, each `since` the leg's own squash landing (`git log --diff-filter=A`), each path present at the new pin, and none placed by a row or declared before:

- **`opendox_code`, 25**: #65 (T088) 1, #67 (T070) 1, #69 (T072) 1, #71 (T085) 2, #72 (T073) 1, #74 (T081) 1, #77 (T084) 9, #78 (T099) 1, #80 (T103) 1, #81 (T102) 1, #82 (T100) 2, #84 (T104) 3, #85 (T102 follow-on) 1. All are openDox-code landings over `047bb4fa..dede32b4`.
- **`openxdox_code`, 4**: #37 (T086) at `56e1c238`: `src/openxdox/column_contributions.py`, `tests/test_column_contributions.py`, `tests/test_column_contributions_governed.py` and `tests/test_host_plane.py`.
- **One leaves: `src/opendox/consumer_reach.py`** (openDox-code#9, `da8aae96`). openDox-code#77 (T084) deleted it at `e49b17c3` when it retired the reach module, so the walk at `dede32b4` never consumes the admission and the verifier would report it stale (`declared_admissions_unused`). It is removed, as split-opendox § 3.4 slice S5 removed its two re-homed modules', and `tests/carve_arrival` asserts it ABSENT. openXdox-code's own `src/openxdox/consumer_reach.py` (the RULED seed) is still at `56e1c238`, and its entry stays.
- Neither spec leg moved (`f7ee3c76`, `f088b097`), so neither admits anything.
- **Derived, not run green, for the `-code` legs**, as at T047 and T064: the walk, with every rule `verify-carve-arrival.py` applies, reports stale 0 and only the carve-time files that are unchanged since the old pins (4 at `opendox_code`, 3 at `openxdox_code`), which T064 left as well (decision (d)).

## T094's "Owed elsewhere" list from opensoft/openXdox-code#37, each item to the file that carries it

- [x] `scripts/opendox_host.register_openxfactory()` calls `column_contributions.register()` after T064's projection line (Q6 (a)): `scripts/opendox_host.py` (`3c1c1146`).
- [x] The module seals: `scripts/ideation_dashboard/dashboard_refresh_lane.py` and `tests/ideation-dashboard/test_dashboard_source_seal.py` (`1c5f8edb`). The carve admissions (`created:` gains `src/openxdox/column_contributions.py`, `tests/test_column_contributions.py`, `tests/test_column_contributions_governed.py` and `tests/test_host_plane.py`): `docs/opendox-carve-admissions.yaml` and `tests/carve_arrival/test_verify_carve_arrival.py` (`b3a4b6e0`).
- [x] The parity test's MRO layout and `test_serve_column_split.py`'s four snapshot rows, which move to the core: `tests/ideation-dashboard/test_extension_point_parity.py` and `tests/ideation-dashboard/test_serve_column_split.py` (`3c1c1146`).
- [x] `test_openxfactory_host_wiring.py`'s "second copy of the column" check and its contributed tuple, which now has three entries: `tests/domain_profile/test_openxfactory_host_wiring.py` (`3c1c1146`): `test_no_route_extension_declares_a_second_copy_of_the_column` holds each column to one declaration, and `CONTRIBUTED_COLUMNS` is `LaneRoutes`, `GateRoutes`, `ProjectionRoutes`.
- [x] The lane route's `hosted_ref_refused(` check (Q8 (a)): `tests/domain_profile/test_lane_route_asks_the_hosted_ref_predicate.py` (`eda75977`).
- [x] The trust policy at T100's seam (openXdox registers none; "Governance approval", #656 comment `5970369724`): `GovernedBindingTrust` in `scripts/opendox_host.py`, tested by `tests/domain_profile/test_host_registers_binding_trust.py` (`3c1c1146`).

## F11.1, on the real commits

`PACKET_MERGE=94b6f7f1… ARC_TIP=<this branch's head>` over the guard extracted from `openspec/changes/add-neutral-product-standalone-operability/tasks.md` prints:

> `requirement 1 holds: 0 note(s) annotated, every other path a declared surface (11.1)`

Every path this PR touches is on a declared surface:

- PIN_PAIRS: `openDox`, `contracts/opendox-pin.yaml`, `openXdox`, `contracts/openxdox-pin.yaml`;
- HOST: `scripts/opendox_host.py`, `scripts/profile_openxfactory.py`;
- HOST_TESTS: `tests/domain_profile/test_host_registers_binding_trust.py`, `tests/domain_profile/test_lane_route_asks_the_hosted_ref_predicate.py`, `tests/domain_profile/test_openxfactory_host_wiring.py`;
- COMPOSITION_TESTS: `tests/ideation-dashboard/test_extension_point_parity.py`, `tests/ideation-dashboard/test_serve_column_split.py`, `tests/ideation-dashboard/test_doxbench_status_exemption.py`;
- ADMITTED_ARC_EDITS: `scripts/ideation_dashboard/dashboard_refresh_lane.py`, `tests/ideation-dashboard/test_dashboard_source_seal.py`, `tests/openxdox_pin/test_openxdox_pin_verifier.py`, `docs/opendox-carve-admissions.yaml` and `tests/carve_arrival/test_verify_carve_arrival.py`.

The admitted list does not grow, and no manifest note is annotated here (decision (b)).

## The falsifiers, at the COMMITTED pins

| run | head | verifiers | `pytest-suite` | other checks |
| --- | --- | --- | --- | --- |
| **CI** | `16136990` | OK, OK | **`selected=9362 passed=9356 skipped=6 failures=0 errors=0`**, floors met (margin 2312), run `37315023063` | all success, `openxdox-consumer-gate` included |
| local | `eda75977` (`16136990` changes only a docstring and a comment) | OK, OK | **8943 passed, 7 skipped, 0 failed** (`pytest tests/ -q -m "not postgres"`) | the composition, `domain_profile`, carve-mapping, both pin dirs and `carve_arrival`: 569 passed |
| **CI** | `7e31eca1` | | PENDING | PENDING |
| local | `7e31eca1` | OK, OK | PENDING | `domain_profile`, the seal and the carve mapping: 626 passed; mutants M12-M19 killed |

Each local run uses Python 3.12.3, with `TMPDIR` and `--basetemp` under `~/.local/state`, outside the aggregation tree, in a checkout named `openxFactory`. A local run skips 7 where CI skips 6: the work tree sits inside an aggregation checkout, so the aggregation ignore-file case runs and passes there (#1215's reason).

- `validate-carve-manifest.py` prints OK (456 rows), and `validate-former-id-arrival.py --base origin/main --head HEAD` passes.

## Accepted limits

- A leg from before T100 now fails with an ImportError, because `seams()` imports `doxbench_trust`, rather than with `HostSeamsIncomplete` by name. The pins only move forward.
- A directory at the declarations path reads as "no document". That is openDox's own store rule (`document_present` checks for a regular file), and the change opens no new hole.
- Under the governed host, `model-binding trust` prints `trusted "m1" on this machine` although `record()` records nothing. That wording is openDox-code's (`cli_model_binding._trusted_line` ignores `recording.recorded`), and it is deferred to an openDox-code follow-on after release 1.
- The trust seam's take-back entry cannot fire today. Only the home seam follows it, and the home seam refuses nothing. Nit: `_TAKE_BACK` is keyed by the bare call name `"register"`.

## What this leaves for the aggregation

This PR does not do the opensoft/xFactory root pin-sync. When it runs, it needs:

- the root `openDox` gitlink → `e1e3a3c3f8dd38214510412b71a2e858c6179532`;
- the root `openXdox` gitlink → `9564d5d9462ffd1a3155d9177206368e5061efa8`;
- the root `openxFactory` gitlink → this PR's landed sha, with `.github/clearing/openxfactory/PIN.yaml` in the same commit (CLAUDE.md rule 2);
- `.github/workflows/dashboard-image-worker.yml`'s `RENDER_LEG_MODULES` and its mirror in `tests/test_dashboard_image_worker_contract.py` gain the same three modules as this PR's `1c5f8edb`.

Arc: neutral-product-standalone-operability

🤖 Generated with [Claude Code](https://claude.com/claude-code)


Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.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.

2 participants