You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
T076, 10.3: the root README documents the one command - #17
Plan 034, task T076, slice P3-O (the root README), phase 3. The plan is specs/034-opendox-standalone-operation/tasks.md at opensoft/openxFactory main ba6bb870. This PR realizes box 10.3 of the ratified add-neutral-product-standalone-operability, as T007 batch H amends it, with the
browser limit of batch P.
5961364221 item 2: T076 was drafted ahead of T063.
5850003126: R1Q15 (b) and R1Q16 (iii), the command itself.
5962754358 item 1, and the holder's ruling of 2026-10-03 (analyze finding H3): until T099 publishes opendox, an install from a recursive clone that keeps the local extra, pip install "./code[local]", stands in for the first line.
5982436447 item 1, "Hint line, accepted limit", and its B7 ruling on the browser's history (12.4a, batch P).
State: this PR still lands before T095, and T089 waits on it. The holder posts READY and the lander merges; this writer does neither.
What it waited on has landed
T087 landed as openDox#18 (e1e3a3c3, 2026-10-05): the root now pins openDox-code dede32b4, the 0.1.0 version bump, with #84 (T104) and #78 (T099's release workflow) inside it. I merged that main into this branch as a merge commit (4fddf62f; the diff against main is README.md only, and the merge took no conflict).
#84 (T104) landed as openDox-code 32943cbf. The "Opening the page" paragraph was written against its design and is now checked against the landed code (below).
Still to come, and not this PR's: T099's later root PR replaces the "Where opendox comes from" paragraph with the PyPI line after the publish verifies. This README keeps that paragraph until then.
What changes: README.md only, 82 lines added
A new section, "Install and run", sits after "Get started". Nothing else moves: the doc index (the docs/ table), the section order, Makefile, every pin and every workflow are untouched.
The command, as batch H's 10.3 addendum reads
The addendum (openspec/changes/add-neutral-product-standalone-operability/tasks.md, 10.3, "AMENDED -- T007 Batch H (5850003126; Ruled R1Q15 (b), R1Q16 (iii))") says, verbatim, at openxFactory mainba6bb870:
The command the root's README.md documents is the standalone install and its one start: pip install "opendox[local]", then opendox generate-and-open --local …. The flag selects the local mode explicitly (13.4 as this batch amends it), and the local extra carries the bundled server that mode starts (13.1 as this batch amends it). After the install, that start is the single command requirement 10's second scenario has a user run. The entry point is still the code leg's console script, and no Makefile target is added, for the reason above. Carried out by T070 and T076.
The README block, character for character (the … is U+2026, preceded by one space):
A mechanical comparison, run on this branch's README.md against that addendum paragraph at openxFactory mainba6bb870:
addendum commands: ['pip install "opendox[local]"', 'opendox generate-and-open --local …']
README has the line 'pip install "opendox[local]"' exactly: 1 time(s); bytes ok=True
README has the line 'opendox generate-and-open --local …' exactly: 1 time(s); bytes ok=True
For the T095 holder check. T095's harness (openDox-code#75, another writer) runs the same command literally. Compare its install line and its start line with the two lines above. The only legitimate difference is that the harness fills the …, as quickstart.md § 3 does: opendox generate-and-open --local --repo-root "$R" --repository fixture --no-open --port "$PORT". Every flag in that line is named in the README's prose, and the harness reads the token from the private copy that the "Opening the page" paragraph describes.
What the … stands for (said in a sentence, no flag invented)
The README says the … stands for the verb's own arguments, which follow it as every option does (10.1 of the change). Two are required: --repo-root (the plain git repository of Markdown documents to open, front matter not required, AT-R1 step 3 (b)) and --repository (a name for it, recorded as the snapshot's repository id). It says the served actor is that repository's git config user.name, that --actor is only a claim that must match an identity the install can establish, and what the start does without an actor. --no-open launches no browser, --port N fixes the port, and opendox generate-and-open --help lists the rest.
Checked against the pin, dede32b4
I installed this root's pinned code leg (dede32b4, version = "0.1.0") into a fresh venv with pip install "./code[local]" (from a copy of the submodule, so this clone stayed clean), and ran the documented start on a three-file plain git repository with no database, broker or model:
Program name and install:opendox --help prints usage: opendox, pip list shows opendox 0.1.0 with pixeltable-pgserver, and the local extra installs.
The local start:/capabilities answers install.mode == "local". The bundled postgres is the entry point's child and is gone, with the port free, after a SIGTERM to the entry point I started. --host 0.0.0.0 under --local is refused.
Host check:Host: 127.0.0.1:<port> got 200, and Host: evil.example got 403.
The console copy, with a git identity: the start printed console file:///<state>/console/<port>.html (this user's private copy, mode 0600: open it to open the console page again), then the hint line, then the plain http://127.0.0.1:<port>/index.html. The copy was mode 600 and began with its marker comment. No printed line held the token, /capabilities carried no console_token, and the copy was gone after the stop.
The hint line: the README quotes it, and a script confirmed the quoted text equals console_access.UNOPENABLE_HINT at the pin, character for character.
Without an actor (no user.name, or --actor stranger): session and edit read false, no console/ directory is made, and only the plain URL is printed.
The state directory: one inside the served repository is refused by name (lies inside the served repository), and the bundled postgres that had started before the refusal is gone. (A directory that holds the repository is refused by name too, which I checked at #84's merge commit 32943cbf.)
The README's claims about a browser (the browser is opened through the copy without --no-open, the Snap, Flatpak and WSL limit, and the history limit) come from #84's landed design, the printed hint and the rulings. A browser is what AT-R1's browser half (T096) exercises, and I did not run one here.
Where the package comes from (no PyPI release is claimed)
Neither the addendum nor quickstart.md names an index for the first line. The README says: opendox is the distribution the code leg builds (code/, opensoft/openDox-code at the commit contracts/code-pin.yaml pins); its pyproject.toml names it opendox and declares the local extra and the opendox console script; and, as of 2026-10-04, no release of it is published to PyPI, so the first line has nothing to resolve from the default index. Until one is, the same distribution and extra install from a recursive clone, run from its root, with pip install "./code[local]" in place of the first line, and the second line runs unchanged. That is the stand-in T076's plan entry names.
Checked again on 2026-10-05, the day T087 landed (the 0.1.0 bump is in the pin, and nothing is published):
Makefile has a row in contracts/shape-pin.yaml (path: Makefile), so a run target would be reported as drift and would red make pins. README.md has no row (grep -n "path:" contracts/shape-pin.yaml lists ten paths, none of them README.md). The README says so in one sentence, and the entry point stays the code leg's console script.
Falsifier
T076's falsifier is review, and AT-R1 step 4 follows it literally. AT-R1 step 4 reads: "The ONE command the openDox root README documents, opendox generate-and-open --local … (R1Q15 (b)), serves the bundle on loopback." The README states the --local command in exactly that spelling, and it is followed literally. Before the cut, the first line cannot be followed literally, because opendox is on no index, so the README's dated paragraph names the checkout install that stands in for it. By the plan's own review criteria, the README also names the browser limit and the OPENDOX_STATE_DIR remedy, and never prints or asks for the console token.
The root's own checks (make validate, which runs the same three scripts the validate workflow's steps run, and make pins), at this PR's head, with both legs initialized (git submodule update --init):
$ 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
$ make pins
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
Review notes
Rounds 1 to 8. Copilot's threads are all resolved: the Python 3.12 prerequisite, the pending T087 pin (now landed), and the console file's actor condition. Other rounds added what landed on openDox-code main: the bundled server and the Host rule (T072, T103), the POSIX and non-root prerequisites, the accepted browser limit (5982436447 item 1) with the hint line quoted, the stale-tab limit, and the history limit (B7). The README never prints or asks for the console token.
This head is the merge of main at T087 on top of those rounds, with no change to the README's text.
No closing keyword appears in this body or in any commit.
Plan 034, task T076, slice P3-O. The root README gains an "Install and run"
section after "Get started". It gives the two lines T007 batch H's 10.3
addendum reads, character for character: pip install "opendox[local]", then
opendox generate-and-open --local … (R1Q15 (b), R1Q16 (iii)).
It says in prose what the "…" stands for (the verb's two required arguments,
--repo-root and --repository, and the options that exist in cli.py), where the
opendox distribution comes from (the code leg, since no release is published
to PyPI), and why no Makefile target is added (it has a shape-pin row).
README.md only. The doc index, the Makefile and every pin are untouched.
Arc: neutral-product-standalone-operability
Lane: openxfactory-4 (openXfactory-4-openDox_extraction)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Adds a root README section documenting the two-line standalone install/start workflow, its arguments and local runtime behavior, the current checkout-based installation fallback, and the intentional absence of a Makefile target; no other files or pins change.
Sequence diagram for the standalone install and local run
sequenceDiagram
actor User
participant Pip
participant CodeLeg
participant OpenDox
participant LocalServer
User->>Pip: pip install "opendox[local]"
Pip->>CodeLeg: Install opendox with local extra
User->>OpenDox: generate-and-open --local …
OpenDox->>LocalServer: Start bundled server on loopback
LocalServer-->>OpenDox: Serve generated snapshot
OpenDox-->>User: Print or open local URL
Loading
Flow diagram for checkout-based standalone installation
flowchart LR
Clone["Recursive clone of openDox"] --> Install["pip install ./code[local]"]
Install --> Start["opendox generate-and-open --local …"]
Start --> Serve["Serve snapshot on loopback"]
Loading
File-Level Changes
Change
Details
Files
Document the standalone installation and startup workflow in the root README.
Add an “Install and run” section with the ruled install line and opendox generate-and-open --local … command.
Explain required repository arguments, optional runtime flags, local-mode behavior, and the meaning of the ellipsis.
Document that the package currently requires installation from the checked-out code/ leg because no PyPI release exists.
Clarify that no Makefile target is added and the code leg’s console script remains the entry point.
README.md
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!
…view round 1)
Copilot's review of the first head asked for the interpreter floor to be
stated before the installation block: the code leg's pyproject.toml declares
requires-python >= 3.12, so an older pip rejects the install before the start
command can run. README.md gains one sentence, before the two lines, which are
unchanged.
Arc: neutral-product-standalone-operability
Lane: openxfactory-4 (openXfactory-4-openDox_extraction)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ound 2)
The README's two command lines are the ruled addendum text and are unchanged.
The prose around them now states only behavior landed on openDox-code main
(1130e996): --local selects the local mode, it needs no identity broker and
binds loopback only, and the flags named are the ones generate-and-open
declares there.
Removed until their tasks land: the bundled server and the local extra (T072,
openDox-code#69), "the bundled server stops when the command does", and the
checkout fallback's [local] extra, which main does not declare yet (pip warns
"does not provide the extra 'local'"). The fallback reads pip install ./code.
The PyPI date is re-checked: still no release on 2026-10-03.
Arc: neutral-product-standalone-operability
Lane: openxfactory-4 (openXfactory-4-openDox_extraction)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Plan 034 T076, on the holder's refresh word. The two command lines are the
ruled addendum text and are unchanged. The prose around them now reads against
openDox-code main (c4b55cc4) and T104's draft head (182cac76):
- H3: the stand-in for the PyPI line is pip install "./code[local]", not a bare
./code. T072 has landed, so the extra exists and the --local start needs it.
The provenance paragraph names the extra again, and its PyPI date is
re-checked (2026-10-04, still 404).
- T072: the local extra carries the runtime packages and the bundled PostgreSQL
server; the start launches it as its own child under OPENDOX_STATE_DIR (no TCP
port) and stops it when the command stops.
- T103: the server answers only a request whose Host names it; any other gets
403 invalid_host.
- T104 (pending openDox-code#84): the start writes a private copy of the
console's opening page and prints its file:// URL, never the token, with or
without --no-open; opening that file opens the page again.
README.md only. Merging openDox main was a no-op (main is still d509829).
Arc: neutral-product-standalone-operability
Lane: openxfactory-4 (openXfactory-4-openDox_extraction)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ctor (review round 3)
Copilot's review of 18c23bf asked the README to document the fallback when no
trusted actor is available. Checked at openDox-code#84's head (182cac76) with
the documented start on a plain git repository:
- no git user.name at all, or --actor naming someone the checkout cannot
establish: /capabilities answers session false and edit false, no console
file is written, and the start prints only the plain
http://127.0.0.1:<port>/index.html;
- user.name set, or --actor matching it: session and edit true, and the start
prints the console file:// URL.
The README now says the served actor is the repository's git user.name, that
--actor is only a claim that must match an identity the install can establish,
and what the start does without an actor. The two command lines are unchanged.
Arc: neutral-product-standalone-operability
Lane: openxfactory-4 (openXfactory-4-openDox_extraction)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…rivate copy (round 5)
Brett's ruling on openxFactory#656 (comment 5982436447, item 1, "Hint line,
accepted limit"): a Snap or Flatpak browser, and a Windows browser running
under WSL, cannot open the private file:// copy under ~/.local/state. T104
(openDox-code#84) will print one extra line, with no token, and the README
documents the same limit and its remedy in the "Opening the page" paragraph:
set OPENDOX_STATE_DIR to a non-hidden folder and restart.
Written against the ruling, not against #84's wording: #84's head (fb8a1cc4)
does not print the line yet. The two command lines are unchanged.
Arc: neutral-product-standalone-operability
Lane: openxfactory-4 (openXfactory-4-openDox_extraction)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The reason will be displayed to describe this comment to others. Learn more.
Copilot review overview
🔵 Needs a closer look
The documented workflow still awaits T087’s pin update and verification against T104’s final behavior.
Review effort: Balanced Findings: None
Previously missed (1)
In code that hasn't changed since last review
Document POSIX and non-root prerequisites for local startup
README.md:29
Document the platform and user prerequisites alongside Python. In openDox-code at c4b55cc4, src/opendox/runtime/bundle.py:135–163,859–867 rejects platforms without the required POSIX primitives and refuses root execution. The documented local start therefore fails on native Windows or when run as root. State these restrictions before the installation block.
…lock (review round 5)
Copilot's review of 5b0990a noted, outside any thread, that the documented
local start fails on a platform without the POSIX primitives and when run as
root. Read at openDox-code main (38d3350e), src/opendox/runtime/bundle.py:
unsupported_platform() (lines 135-163) refuses a platform that lacks them and
names it, and BundledServer.start() (lines 859-867) refuses to run as root.
README.md gains one sentence beside the Python prerequisite. The two command
lines are unchanged.
Arc: neutral-product-standalone-operability
Lane: openxfactory-4 (openXfactory-4-openDox_extraction)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
openDox-code#84 landed as 32943cbf. Read against it, the README's "Opening the
page" paragraph is right on how the page is opened (the private copy, its
file:// URL, never the token, the plain URL loading without it), on the actor
condition, on the program name (opendox) and on the install line. Three
changes:
- The browser limit now uses the ruled and printed wording (5982436447, item 1;
plan 034 T076 and 12.4a's batch P amendment): an accepted limit of release 1,
the hidden default state directory (~/.local/state/opendox), Ubuntu's default
Snap browser, a Flatpak browser and a Windows browser under WSL, and the hint
line quoted as T104's start prints it (console_access.UNOPENABLE_HINT).
- The remedy names what the start refuses (checked on 32943cbf): a state
directory inside the served repository, or one that holds it, is refused by
name, so the folder must be apart from the repository.
- 12.4a's stale-tab limit: each start makes a new token, so after a restart
open the new file.
README.md only. The two command lines are unchanged.
Arc: neutral-product-standalone-operability
Lane: openxfactory-4 (openXfactory-4-openDox_extraction)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…cal)
12.4a's accepted limit (T007 batch P, the holder's ruling B7): the browser's
own history keeps the opened URL, fragment included, until it is cleared. Each
start makes a new token, so an entry from an earlier start grants no access.
One sentence in "Opening the page", after the stale-tab sentence. The README
still never prints or asks for the token. The two command lines are unchanged.
Arc: neutral-product-standalone-operability
Lane: openxfactory-4 (openXfactory-4-openDox_extraction)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
brettheap
changed the title
DRAFT (phase 3, after T063): T076, 10.3: the root README documents the one command
T076, 10.3: the root README documents the one command
Oct 5, 2026
READY at 4fddf62 — Lane: openxfactory-4 (openXfactory-4-openDox_extraction)
Holder: T076, 10.3: the root README documents the one command. It is an arc landing.
The command. The README gives pip install "opendox[local]" and opendox generate-and-open --local …, byte for byte as batch H's addendum has them. Until T099 publishes, the dated paragraph's stand-in is pip install "./code[local]".
What #84 changed, aligned. The console copy is a private file:// URL, the token is never printed, and the program is named opendox. The browser limit is quoted character for character from console_access.UNOPENABLE_HINT, and the stale-tab and history limits (12.4a) are named.
Re-verified at the pin. openDox-code dede32b4, 0.1.0, in a fresh venv. The browser-opening claims rest on #84's landed design; T096 exercises a browser.
Gates.
make validate and make pins pass.
CI validate and SonarCloud are green.
Copilot has no findings.
All 3 threads are resolved.
It merges root main e1e3a3c3 (T087) with no conflict.
…, 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>
brettheap
added a commit
to opensoft/openDox-code
that referenced
this pull request
Oct 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Plan 034, task T076, slice P3-O (the root README), phase 3. The plan is
specs/034-opendox-standalone-operation/tasks.mdat opensoft/openxFactorymainba6bb870. This PR realizes box 10.3 of the ratifiedadd-neutral-product-standalone-operability, as T007 batch H amends it, with thebrowser limit of batch P.
Arc: neutral-product-standalone-operability
Lane: openxfactory-4 (openXfactory-4-openDox_extraction)
5961416935.5961364221item 2: T076 was drafted ahead of T063.5850003126: R1Q15 (b) and R1Q16 (iii), the command itself.5962754358item 1, and the holder's ruling of 2026-10-03 (analyze finding H3): until T099 publishesopendox, an install from a recursive clone that keeps thelocalextra,pip install "./code[local]", stands in for the first line.5982436447item 1, "Hint line, accepted limit", and its B7 ruling on the browser's history (12.4a, batch P).What it waited on has landed
e1e3a3c3, 2026-10-05): the root now pins openDox-codedede32b4, the 0.1.0 version bump, with #84 (T104) and #78 (T099's release workflow) inside it. I merged thatmaininto this branch as a merge commit (4fddf62f; the diff againstmainisREADME.mdonly, and the merge took no conflict).32943cbf. The "Opening the page" paragraph was written against its design and is now checked against the landed code (below).opendoxcomes from" paragraph with the PyPI line after the publish verifies. This README keeps that paragraph until then.What changes:
README.mdonly, 82 lines addedA new section, "Install and run", sits after "Get started". Nothing else moves: the doc index (the
docs/table), the section order,Makefile, every pin and every workflow are untouched.The command, as batch H's 10.3 addendum reads
The addendum (
openspec/changes/add-neutral-product-standalone-operability/tasks.md, 10.3, "AMENDED -- T007 Batch H (5850003126; Ruled R1Q15 (b), R1Q16 (iii))") says, verbatim, at openxFactorymainba6bb870:The README block, character for character (the
…is U+2026, preceded by one space):pip install "opendox[local]" opendox generate-and-open --local …A mechanical comparison, run on this branch's
README.mdagainst that addendum paragraph at openxFactorymainba6bb870:For the T095 holder check. T095's harness (openDox-code#75, another writer) runs the same command literally. Compare its install line and its start line with the two lines above. The only legitimate difference is that the harness fills the
…, as quickstart.md § 3 does:opendox generate-and-open --local --repo-root "$R" --repository fixture --no-open --port "$PORT". Every flag in that line is named in the README's prose, and the harness reads the token from the private copy that the "Opening the page" paragraph describes.What the
…stands for (said in a sentence, no flag invented)The README says the
…stands for the verb's own arguments, which follow it as every option does (10.1 of the change). Two are required:--repo-root(the plain git repository of Markdown documents to open, front matter not required, AT-R1 step 3 (b)) and--repository(a name for it, recorded as the snapshot's repository id). It says the served actor is that repository'sgit config user.name, that--actoris only a claim that must match an identity the install can establish, and what the start does without an actor.--no-openlaunches no browser,--port Nfixes the port, andopendox generate-and-open --helplists the rest.Checked against the pin,
dede32b4I installed this root's pinned code leg (
dede32b4,version = "0.1.0") into a fresh venv withpip install "./code[local]"(from a copy of the submodule, so this clone stayed clean), and ran the documented start on a three-file plain git repository with no database, broker or model:opendox --helpprintsusage: opendox,pip listshowsopendox 0.1.0withpixeltable-pgserver, and thelocalextra installs./capabilitiesanswersinstall.mode == "local". The bundled postgres is the entry point's child and is gone, with the port free, after a SIGTERM to the entry point I started.--host 0.0.0.0under--localis refused.Host: 127.0.0.1:<port>got 200, andHost: evil.examplegot 403.console file:///<state>/console/<port>.html (this user's private copy, mode 0600: open it to open the console page again), then the hint line, then the plainhttp://127.0.0.1:<port>/index.html. The copy was mode 600 and began with its marker comment. No printed line held the token,/capabilitiescarried noconsole_token, and the copy was gone after the stop.console_access.UNOPENABLE_HINTat the pin, character for character.user.name, or--actor stranger):sessionandeditread false, noconsole/directory is made, and only the plain URL is printed.lies inside the served repository), and the bundled postgres that had started before the refusal is gone. (A directory that holds the repository is refused by name too, which I checked at #84's merge commit32943cbf.)The README's claims about a browser (the browser is opened through the copy without
--no-open, the Snap, Flatpak and WSL limit, and the history limit) come from #84's landed design, the printed hint and the rulings. A browser is what AT-R1's browser half (T096) exercises, and I did not run one here.Where the package comes from (no PyPI release is claimed)
Neither the addendum nor quickstart.md names an index for the first line. The README says:
opendoxis the distribution the code leg builds (code/,opensoft/openDox-codeat the commitcontracts/code-pin.yamlpins); itspyproject.tomlnames itopendoxand declares thelocalextra and theopendoxconsole script; and, as of 2026-10-04, no release of it is published to PyPI, so the first line has nothing to resolve from the default index. Until one is, the same distribution and extra install from a recursive clone, run from its root, withpip install "./code[local]"in place of the first line, and the second line runs unchanged. That is the stand-in T076's plan entry names.Checked again on 2026-10-05, the day T087 landed (the
0.1.0bump is in the pin, and nothing is published):No
MakefiletargetMakefilehas a row incontracts/shape-pin.yaml(path: Makefile), so aruntarget would be reported as drift and would redmake pins.README.mdhas no row (grep -n "path:" contracts/shape-pin.yamllists ten paths, none of themREADME.md). The README says so in one sentence, and the entry point stays the code leg's console script.Falsifier
T076's falsifier is review, and AT-R1 step 4 follows it literally. AT-R1 step 4 reads: "The ONE command the openDox root README documents,
opendox generate-and-open --local …(R1Q15 (b)), serves the bundle on loopback." The README states the--localcommand in exactly that spelling, and it is followed literally. Before the cut, the first line cannot be followed literally, becauseopendoxis on no index, so the README's dated paragraph names the checkout install that stands in for it. By the plan's own review criteria, the README also names the browser limit and theOPENDOX_STATE_DIRremedy, and never prints or asks for the console token.The root's own checks (
make validate, which runs the same three scripts thevalidateworkflow's steps run, andmake pins), at this PR's head, with both legs initialized (git submodule update --init):Review notes
main: the bundled server and theHostrule (T072, T103), the POSIX and non-root prerequisites, the accepted browser limit (5982436447item 1) with the hint line quoted, the stale-tab limit, and the history limit (B7). The README never prints or asks for the console token.mainat T087 on top of those rounds, with no change to the README's text.🤖 Generated with Claude Code