Repository navigation
T062, phase 2's openDox root pin: code → 047bb4fa (plan 034, T090 steps 1–2) - #16
Conversation
…anded; plan 034) Move the `code` gitlink and `contracts/code-pin.yaml` (`commit:` and `digests.tree_sha256`) to openDox-code's main, 047bb4fa, which carries every phase-2 openDox-code landing: T050 (dc3765dd), T051 (86647320), T052 (fa8862cc), T054 (a691e4e4), T057 (8ec08e91), T055 (fa140875) and its follow-up #70 (75bd8703), T056 (a23e4224) and T058 (047bb4fa). This follows T053's spec pin and bundle in this root (openDox#14 -> 5200521, the dox-v1.1 tag, then #15 -> 6675843) and T039 (#13 -> 663ac68). 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>
Reviewer's guide (collapsed on small PRs)Reviewer's GuideThis PR performs the phase-2 openDox root pin update by advancing the code gitlink and synchronized contract pin from 2d116415 to 047bb4fa, updating the verified tree digest, and confirming the lockstep and repository validation checks pass without changing the spec leg or bundle. Flow diagram for the synchronized openDox code pin updateflowchart LR
A[openDox code gitlink<br/>2d116415] -->|advance to| B[openDox-code phase-2 landing<br/>047bb4fa]
C[contracts/code-pin.yaml<br/>commit and tree_sha256] -->|update in lockstep| D[commit: 047bb4fa<br/>tree_sha256: 97536dbe]
B --> E[make pins]
D --> E
E --> F[ pins ok ]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The gitlink and contract pin are synchronized, satisfy the documented task, and introduce no unresolved issues.
Review effort: Balanced
Findings: None
What changed in this PR
Advances the openDox assembly’s code leg to the completed phase-2 revision required by T062/T090.
Changes:
- Updates the
codegitlink to047bb4fa. - Synchronizes the contract pin and tree digest.
| File | Description |
|---|---|
code |
Advances the code submodule revision. |
contracts/code-pin.yaml |
Updates 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.
|
READY at ef7e83f — Lane: openxfactory-4 (openXfactory-4-openDox_extraction) |
…t (plan 034 T059) T062 (opensoft/openDox#16) landed as d5098297. It pins openDox-code 047bb4fa394f3e1bf42466062a67ef18e99f8d6a, the head of openDox-code main after T058 (#68). So this leg's `opendox @` pin moves from 814516b7 (the head of openDox-code#59) to that commit. The pin crosses, first-parent: T057 (#58, 8ec08e9), T055 (#59, fa14087) and its follow-up (#70, 75bd870), T056 (#66, a23e422) and T058 (#68, 047bb4f). The repository has no lock or constraints file, so pyproject.toml is the one place the pin lives. One seam moved. T058 replaced default_projection.VALIDATOR, one stand-in for all of openDox's own kinds, with VALIDATORS, one validator per own kind. So tests/test_projection_contributions.py reads VALIDATORS[kind] in its two cases. That file is T059's own and not a protected suite. The pin comments were re-measured at 047bb4fa, and each measurement holds: * ViewBinding still takes exports and styles (dataclasses.fields); * _back_import_census() returns the same three rows as the ratchet table; * openDox's NEUTRAL_MODULES is still thirteen, with STILL_REACHING empty; * the vendored stylesheet helpers and GATE_EXCLUSIVE are byte-unchanged in tests/test_binding_stylesheets.py. The whole suite, alone at the new pin, gives 989 passed, 4 skipped and 1 deselected (CI's command), the triple unchanged. Lane: openxfactory-4 (openXfactory-4-openDox_extraction) Arc: neutral-product-standalone-operability Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…e through openDox's seams (5.4a) (plan 034) (#35) Lane: openxfactory-4 (openXfactory-4-openDox_extraction) Arc: neutral-product-standalone-operability **DRAFT. T062 has landed, and this PR is pinned to its commit.** - **T062** landed as opensoft/openDox#16, merge commit `d5098297`. It pins openDox-code `047bb4fa` (`047bb4fa394f3e1bf42466062a67ef18e99f8d6a`), the head of openDox-code `main` after T058. - `pyproject.toml`'s `opendox @` pin now names that commit, at `25414afc`. Before that it named `814516b7`, openDox-code#59's head while that PR was a draft. - The comments that name the pin were each re-measured at `047bb4fa`. They are in `src/openxdox/view_extensions.py`, `tests/test_dependency_direction.py`, `tests/test_gate_loop_probes.py`, `tests/integration/test_assembled_bundle.py` and `validate.yml`. - **T055** landed as openDox-code#59 (`fa140875`). Between the two pins sit T057 (#58, `8ec08e91`), T055's follow-up (#70, `75bd8703`), T056 (#66, `a23e4224`) and T058 (#68, `047bb4fa`). - **The holder retargets T061 (openXdox-code#36, stacked on this branch) to `main` before this PR goes READY.** A `--delete-branch` landing would close it. ## What this is This PR carries plan 034's **T059** (`specs/034-opendox-standalone-operation/tasks.md`, read at openxFactory `main` `91e4685f`), slice P2-K: **5.4a, openXdox contributes its governed generator, registry and source through openDox's seams**. It is the governed half of R1Q10 (a). - **Realizes**: 5.4a, and 9.5 (step 3, part). - **Ruled**: R1Q6 (d), R1Q7 (a), `5817152735`; R1Q10 (a), R1Q23 (a), `5850003126`; R1Q26 (a), `5851950767`. - **After**: T052 (landed, openDox-code#54 → `fa8862cc`), T055 (landed, openDox-code#59 → `fa140875`), T060 (landed, openXdox-code#34 → `c41063d6`), T062 (landed, openDox#16 → `d5098297`), T067 and T007's batches C and I (landed; batch I is openxFactory#1180 → `8421603a`), and T040 (landed, openXdox-code#29), for the ratchet's single-writer order. openXdox keeps `generator.py`, `snapshot.py`, `snapshot_registry.py`, `completeness.py` and `corpus_root.py`. The new `openxdox.projection_contributions` registers what they provide at openDox's seams: | seam | openXdox's contribution | |---|---| | `opendox.generator_seam` | `GENERATOR`, a `SnapshotGenerator` over `generator.generate_snapshot`, declaring its two inputs (`project_register_source`, `possibles_source`) | | `projection_seams.registry` | the `snapshot_registry` module | | `projection_seams.corpus_root` | `CORPUS_ROOT`: `corpus_scan_defect`, `corpus_root_refusal`, `change_rows` and `SCANNED_ROOTS` | | `projection_seams.writer` | the `snapshot` module (`write_snapshot`) | | `projection_seams.validators` | `VALIDATOR`, for the three governed kinds (`ideation-dashboard-snapshot`, `-index`, `gate-action-record`). openDox's own kinds keep openDox's validator. | `generator`, `corpus_root` and `completeness` import openxFactory's `doc_health` at module level, and a lone checkout does not carry it (R1Q6 (d); the direction arc is T008). So the contributions reach those modules late, when they are used. Registering reaches no module that needs `doc_health`, and a subprocess case holds that with `doc_health` blocked. `register()` is explicit, idempotent, and all or none. A seam's refusal (`GeneratorAlreadyRegistered`, `SeamAlreadyRegistered`) reaches the caller unchanged, after every seam that call wrote has been taken back, in reverse. `is_registered()` and `unregister()` complete the API. ## The holder's rulings on this PR Each of these is the holder's reading, given on this PR's questions. 1. **Where the contributions register: (c), not (a).** - `openxdox.projection_contributions.register()` is an explicit call. - `openxdox.domain_profile.register()` calls it too, so openXdox standalone gets its governed projection from its own registration path. - `domain_profile.load()` stays free of side effects. Registering from `load()` was option (a), and it was ruled out: it would fire in every process that only reads a profile (the verifiers, the NotebookLM sync, tests). - **This revises the holder decision in openDox-code#54's body (2026-09-27).** That decision read: "T059 registers openXdox's generator from openXdox's own profile-registration path, the hook openxFactory already calls. So T064's line stays true, and T064 needs no host line." It rested on a misread. openxFactory's `scripts/opendox_host.register_openxfactory()` never calls `openxdox.domain_profile.register()`: it calls `openxdox.domain_profile.load(PROFILE_PATH)` and registers the composite with openDox alone (`opendox.domain_profile.register(composite)`). - **So T064 owes one host line:** `openxdox.projection_contributions.register()` in `register_openxfactory()`. T064's line *"It composes openXdox's profile, so none is expected"* no longer holds. `scripts/opendox_host.py` is on F11.1's host surface, so its guard admits the change. 2. **The home corpus in the test harness: (c).** openDox's `authoring.create_scaffold` asks the registered home corpus which fields it obliges (`scaffold_lead_fields()`, T054). With nothing registered it refuses, as #1144's 4.1a has every seam do: > "A process in which no entry point was built and nothing registered anything — an import, a test, a library caller — still refuses with 4.2's ADAPTER_NOT_REGISTERED, so the default is a registration the entry point makes and never a fallback inside the seam." That rules out (a), a fallback inside the seam, and (b) would amend a ruled falsifier environment. So `tests/conftest.py` registers the same factory openxFactory's host registers, `corpus_adapter_openxfactory.home_corpus`, found where F5.2's environment composes openxFactory's `scripts/` on `PYTHONPATH`. Where it is absent, it registers nothing, and a lone checkout refuses as 4.1a says. - **`tests/conftest.py` is not a protected suite.** It matches neither F5.2's glob (`tests/test_generator.py`, `tests/test_snapshot*.py`, `tests/test_session_snapshot.py`) nor 12.5's computed set (`git grep -l -e open-pr -e open_pr -e FakePullRequests -- 'tests/test_*.py'`). So it has no allow-list entry. - **The declared-exclusion accounting is unchanged by it.** Every suite that reaches the home corpus also reaches `doc_health`, so each is already declared. The lone whole suite is green with nothing registered. - **The cases are green again**, measured in composition (below). At `e3ef506a` there were 69. At `814516b7` there are 71, the same 69 plus the 2 T054's final head routes through the home corpus. All 71 pass here. 3. **The respelling: accepted** as an R1Q7 (a) entry citing T055's `r4136863569`. The expected call in `tests/test_session_snapshot.py::test_the_session_source_read_is_the_existing_confinement_mechanism` is respelled from `self.source.registry.resolve_source(` to `resolve_source_path(Path(root), rest)`, the route's one entry point, which applies the registered registry's `resolve_within`. The second assertion is unchanged. 4. **The consumer-schema reds: (a).** In F5.2's environment, seven cases are red at BOTH pins because the consumer's schemas are not in a lone tree: `test_generator.py` 4, `test_snapshot_determinism.py` 1 and `test_snapshot_registry.py` 2. They are deselected in T059's F5.2 run with R1Q25 (b)'s reason. A supplementary run with a composed `CONTRACTS_DIR` shows all seven green (below). `test_snapshot_validation_launch.py`'s 5 reds are C3's, so they are T061's. 5. **The exclusion entry: accepted.** T059 removes `tests/test_seam_assembly_beside_gate_and_projection.py` from `tests/declared_exclusion.yaml`, taking it from 67 to 66 files. The file was declared under `doc_health` only because `serve_projection` reached `doc_health` through `snapshot_registry` at import. `snapshot_registry`'s one read of `doc_health` (`pin_sentinels`) now happens where the sentinel is written, so the file passes alone in a lone checkout, and T041's `test_declared_exclusion` would refuse it as declared. **T059 joins the exclusion file's single-writer chain between T044 and T061:** T044 → T059 → T061. 6. **Three pre-arc reds in `tests/test_session_snapshot.py`: (a)**, ruled after this PR opened. They are deselected in T059's F5.2 run with the reason "red at both pins; pre-arc carve residue; not the arc's", and this PR does not edit them. They stay open for F5.2 whole (T061/T063). - `test_a_new_serve_process_re_registers_the_session_at_startup`: `opendox.serve` has no `SNAPSHOT_INDEX_ROUTE`. The constant moved to `openxdox.serve_projection` in split-opendox § 2.4 PR-3 (#761). - `test_a_session_key_is_validated_against_the_roster_before_url_composition`: the node probe copies only `repo-selector-model.js`, which imports `./display.js` (since openDox-code#21, § 3.4 S7). - `test_the_hosted_session_arrival_path_is_recorded_and_not_built`: `_handle_refresh_action` is not on openXdox's serve surface. It moved to openxFactory's `serve_openxfactory_lanes.py` in § 2.4 PR 3. ## What changes | path | what changes | |---|---| | `src/openxdox/projection_contributions.py` | **Created.** The contributions, as above. | | `src/openxdox/domain_profile.py` | `register()` also registers the contributions, after its own refusals and before the profile is held, so a refused contribution leaves no profile registered. `unregister()`'s docstring says why the contributions stay (below). | | `src/openxdox/snapshot_registry.py` | Reads `pin_sentinels` only where it writes the sentinel, for an entry with no revision. Seals gaps 1, 2 and 4 below. `index_document` and `compose_aggregate` each take one reading. | | `src/openxdox/snapshot.py` | Seals gap 3 below. `SnapshotNotWritable` is a `ProjectionSeamError` and a `ValueError`. | | `scripts/protected_suites.py` | **Created.** Batch C's subtraction (below). | | `tests/test_projection_contributions.py` | **Created**, 22 cases. | | `tests/test_governed_registry_and_writer.py` | **Created**, 27 cases, one or more per gap. | | `tests/test_protected_suite_check.py` | **Created**, 43 cases, over scratch git histories. | | `tests/test_gate_loop_views.py` | **Protected (12.5).** Batch I's second admitted edit, entered. | | `tests/test_session_snapshot.py` | **Protected (F5.2).** The respelling, entered. | | `tests/protected_suite_respellings.yaml` | Entries 2 and 3. The header now says who reads the file and states the named-test condition. | | `tests/conftest.py` | The home corpus, as ruled (2 above). | | `tests/test_generated_at_anchor.py` | Patched `snapshot._locate_validator`, which openDox's generate verb no longer reaches. It now patches the registered validator's `locate()`. | | `tests/test_dependency_direction.py` | The ratchet is lowered for T055's reaches: `cli` and `serve` leave `OPENDOX_BACK_IMPORTS`, and `branch_session` goes from (0, 7) to (0, 2). `DOC_HEALTH_SURFACE` records `snapshot_registry` as (0, 1). | | `tests/declared_exclusion.yaml`, `tests/test_declared_exclusion.py`, the four seam files | The exclusion entry leaves (5 above), and the prose follows. | | `pyproject.toml` | The pin: `2d116415` → `047bb4fa`, T062's commit. In the drafts it named `814516b7`, #59's head. | | `.github/workflows/validate.yml` | Floors raised to CI's reading, with the reason. The prose that named the old pin or the declared file is updated. | | `src/openxdox/view_extensions.py`, `tests/test_gate_loop_probes.py`, `tests/integration/test_assembled_bundle.py` | Comments that name the pin follow it, each measured at `814516b7` and again at `047bb4fa`, where each claim still holds. `ViewBinding` still has `styles` and `exports`. `web/`, `view_extension.py` and the copied stylesheet helpers are unchanged from `2d116415`. | | `tests/test_projection_contributions.py` (at `047bb4fa`) | One seam moved in T058: `default_projection.VALIDATOR`, one stand-in for all of openDox's own kinds, became `VALIDATORS`, one validator per own kind. The two cases that name it read `VALIDATORS[kind]`. This file is this PR's own, not a protected suite. | | `src/openxdox/projection_contributions.py` (at `aa0a2c5d`) | A refused registration gives back each unread default it replaced, as the default it was, instead of leaving the seam empty (Copilot, r4149710491). | **A kept decision on teardown.** Copilot asked whether `domain_profile.unregister()` should release the contributions. It does not. The contributions belong to the process, not the profile: - a host registers them without this module too (T064); - openDox's seams refuse a governed registration once a default has been read. So a teardown that took them back could not be undone wherever anything was served from a default in between, and a test fixture that takes the profile away for one case could not put it back. `projection_contributions.unregister()` is their teardown. The docstring says so, and a case pins both halves. ## The four gaps openDox's own defaults sealed each of these in openDox-code#59's review rounds, and #59's body names them as openXdox-code's to seal before T059 registers this leg's mechanisms. 1. **`resolve_within`'s symlink escape (r4125556296).** The hidden-name rule was applied only to the path as the URL spelled it, so `link -> .git` served `/source/link/config`, and `notes.md -> .env` served `.env`. The rule is now applied to the canonical path too. The source root is resolved under the same guard, so a root that is a symlink loop refuses instead of raising (Copilot). 2. **`drop` left a dangling active key.** Dropping the active entry now clears the key. Left set, it also kept every later entry from becoming active. 3. **The writer.** - It wrote in place (r4126138808). It now writes an exclusive temporary sibling, keeps the target's permission bits, fsyncs, and moves the sibling over the target in one `os.replace`. A failed move leaves the old snapshot and no sibling. - `canonical_json` wrote `NaN` and `Infinity` (r4125900060). A value JSON cannot carry is now refused, with nothing written. 4. **`SnapshotRegistry` read without its lock (r4136863481).** Every read now holds it, and the index and an aggregate's composition are each one reading (Copilot, r4139816732). ## The protected edits, and batch C's wiring **Both edits are entered in `tests/protected_suite_respellings.yaml`, naming this PR:** | entry | suite and test | edit | blobs | |---|---|---|---| | 2 | `tests/test_gate_loop_views.py::test_the_overlay_changes_four_words_and_the_named_absence_and_nothing_else` | admitted (R1Q26 (a), batch I): the test expects the `values` block's six leaves beside the five it pinned | `a56906c6` → `a5ce00cc`, chained on entry 1 | | 3 | `tests/test_session_snapshot.py::test_the_session_source_read_is_the_existing_confinement_mechanism` | respelling (R1Q7 (a), T055's r4136863569) | `b5e1be02` → `f78c4452` | Each is its own commit on this branch (`81a01cd`, `614f79f`), so each entry also holds at its commit. **`scripts/protected_suites.py` is batch C's subtraction** (RULED R1Q7 (a), `5817152735`). It is the last step of F5.2 and of 12.5's falsifier, in place of the inline intersection each ended with: ``` python3 scripts/protected_suites.py --landings="$(cat "$W/x-arc.txt")" --suites="$(cat "$W/gen-suites.txt")" # F5.2 python3 scripts/protected_suites.py --landings="$(cat "$W/x-arc.txt")" --suites="$(cat "$W/governed.txt")" # 12.5 ``` - The falsifier still lists the landings and the protected suites itself. - The script admits a touched suite only where one entry holds at that landing. An entry holds when: - the before and after blobs are the entry's; - `old` occurs once, and replacing it with `new` gives the after text byte for byte; - `old` starts a line, as it ends one; - both lie inside the named test. - Each entry admits one landing. The landings are taken oldest first, so a later landing that repeats a spent entry's edit is refused. - Renames are not detected, so a protected suite renamed away counts as a deletion. - It exits 2, subtracting nothing, when its input or the allow-list breaks the rules, or when the checkout does not hold a landing's history. - The lists are passed as values, never as paths: SonarCloud's first analysis flagged a path read from `argv`, S8707. ## Evidence Every run here used `LANG=C.UTF-8`, in the foreground. **AT THE FINAL PIN, `047bb4fa`, head `aa0a2c5d`.** - **The required check (9.2).** Run `36782773982` reads `triple: selected=993 passed=989 skipped=4 failures=0 errors=0`, which is the same triple as at `814516b7`. So the floors, 993 and 989, already sit on CI's reading at margin 0, and do not move. - **F5.2 in its environment**, on a simulated squash landing of this head on `main`, with `OPENDOX_CODE` at `047bb4fa`, `OPENXFACTORY` at `91e4685f` and `ARC_BASE` at `e28930bf`, with the same deselects as below: - `test_generator` 41 passed, 4 deselected; - `test_session_snapshot` 20 passed, 3 deselected; - `test_snapshot` 15 passed, 2 deselected; - `test_snapshot_determinism` 5 passed, 1 deselected; - `test_snapshot_registry` 38 passed, 2 deselected; - `test_snapshot_validation_launch` 5 failed, 4 passed. These are T061's, as below. - `test_snapshot_validator_home` 12 passed. - The arc check admits `tests/test_session_snapshot.py` by entry 3, then prints `ok: 1 protected edit(s)`. - 12.5's call admits `tests/test_gate_loop_views.py` by entries 1 and 2, and exits 0. - **The supplementary run with `CONTRACTS_DIR` composed**, and no both-pins deselect: `test_generator` 45/45, `test_snapshot_determinism` 6/6 and `test_snapshot_registry` 40/40. So the seven reds at both pins are still only the consumer's schemas. - **Whole suite alone (CI's command):** 989 passed, 4 skipped, 1 deselected. - **Mutants:** 22 of 22 killed at `aa0a2c5d`. That is the 21 below, plus "a displaced unread default is not given back", which fails 1 case. The sections below were measured at `4feb8009` with openDox-code at `814516b7`, the drafts' pin, and are kept as they were. **The required check (9.2), CI's reading.** Run `36741174322` at `4feb8009`: ``` triple: selected=993 passed=989 skipped=4 failures=0 errors=0 pins: selected>=993 (margin 0) passed>=989 (margin 0) skipped==4 ``` `main` `c41063d6` reads 896/892/4. Compared test by test: - added 98: `test_protected_suite_check` 43, `test_governed_registry_and_writer` 27, `test_projection_contributions` 22, and `test_seam_assembly_beside_gate_and_projection` 6; - removed 1: `test_declared_exclusion`'s case for the seam-assembly file; - changed outcome 0, and the same four skips. The floors are raised to 993 and 989 (T060's 11 and T059's 97), with `EXPECT_SKIPPED` 4, margin zero. Each later case moved them again, in its own commit, from CI's reading of the head before. **F5.2 in its environment**, as batch G amends it. That is a fresh venv, `pip install ".[test]"`, then `--force-reinstall --no-deps "$OPENDOX_CODE"`, with `PYTHONPATH="$OPENXFACTORY/scripts"`. `OPENDOX_CODE` is openDox-code `814516b7`, `OPENXFACTORY` is openxFactory `91e4685f`, and `ARC_BASE` is `e28930bf`. The deselects are the task's two `test_snapshot.py` schema cases plus rulings 4 and 6. At this head (`4feb8009`): ``` tests/test_generator.py rc=0 41 passed, 4 deselected tests/test_session_snapshot.py rc=0 20 passed, 3 deselected tests/test_snapshot.py rc=0 15 passed, 2 deselected tests/test_snapshot_determinism.py rc=0 5 passed, 1 deselected tests/test_snapshot_registry.py rc=0 38 passed, 2 deselected tests/test_snapshot_validation_launch.py rc=1 5 failed, 4 passed <- C3's, T061's (ruling 4) tests/test_snapshot_validator_home.py rc=0 12 passed landings: 29 admitted: 614f79f tests/test_session_snapshot.py, by entry 3 of tests/protected_suite_respellings.yaml ok: 1 protected edit(s), each entered and holding ``` The same block, **before**: - at `main` `c41063d6` with `OPENDOX_CODE` at `814516b7` (the realized openDox, pins only): `test_session_snapshot.py` 20 failed (`SeamNotRegistered`, adapter-not-registered), `test_snapshot_validation_launch.py` 9 failed; - at `main` with openDox `2d116415` (the old pin): `test_session_snapshot.py` 3 failed (ruling 6's three), `test_snapshot_validation_launch.py` 6 failed. The five `validation_launch` reds left here are: - `test_the_default_shaped_launch_validates_from_the_repo_root` - `test_a_run_dir_beside_a_checkout_still_uses_that_one_first` - `test_the_dependency_warning_carries_the_pip_remedy_and_clears_the_corpus` - `test_a_non_conformant_snapshot_still_blocks_and_blames_the_snapshot` - `test_the_classifier_reads_the_exit_code_not_the_dependency_sentence` **Supplementary, with a composed `CONTRACTS_DIR`** (ruling 4). The directory holds openXdox-spec `f088b09`'s three schemas, openDox-spec `f7ee3c7`'s three and openxFactory `91e4685f`'s four. The run does not deselect ruling 4's seven: ``` tests/test_generator.py rc=0 45 passed tests/test_snapshot_determinism.py rc=0 6 passed tests/test_snapshot_registry.py rc=0 40 passed ``` The rest reads as above, and ruling 6's three stay red. **12.5's set, and a simulated landing.** Over 12.5's 16 governed suites, the check admits `81a01cd` by entry 2 and `c41063d6` (#34) by entry 1. A squash landing of this branch on `main` was simulated with `git commit-tree HEAD^{tree} -p origin/main`, carrying the `Arc:` line. It is admitted by entry 3 (the F5.2 set) and by entry 2 (the 12.5 set). **With `main`'s allow-list** (entry 1 only), the same landing is refused on both paths: - `tests/test_gate_loop_views.py`: entry 1's before blob is `7321b04d`, and the suite before the landing is `a56906c6`; - `tests/test_session_snapshot.py`: "no entry names this suite". **The 23 protected suites in composition** (openxFactory `scripts/` on `PYTHONPATH`, each suite alone), compared test by test with `main` at the old pin: | state | red where `main` at the old pin was green | green where it was red | |---|---|---| | `main` with openDox `814516b7` (pins only) | 150 (130 `SeamNotRegistered`) | 0 | | this head | **0** | 3 | | this head with the home registration removed from `conftest.py` | 71, all adapter-not-registered | 0 | **Mutants**, at this head. Each ran against its suites, and the file was restored and checked clean after each. All 21 were killed: | mutant | killed by | |---|---| | take-back removed | 3 failed | | `_holds` always true / reads nothing | 11 / 8 failed | | `domain_profile.register` without the contributions | 5 failed | | `resolve_within` without the canonical check | 2 failed | | `drop` keeps the active key | 2 failed | | `get` without the lock | 1 failed | | `allow_nan=True` | 3 failed | | write in place | 2 failed | | no mode copy | 1 failed | | `pin_sentinels` back at module level | collection error, plus the ratchet | | the check skips each of: the before blob, the after blob, the exact text, occurs-once, old inside the test, new inside the test, input shapes, chaining | 1 to 3 failed each | | the facet's `values` block loses one governed word | 2 failed (the protected facet and overlay tests) | | the installed openDox route confines beside `resolve_source_path` | 1 failed (the respelled assertion) | More checks were each shown red before the commit that added them and green after: - the one-window index and aggregate; - the rename; - `schema_version: 1.0`; - the single-use entry and input order, plus `edit: []` and a sequence key; - a source root that is a symlink loop; - a landing the checkout does not hold (exit 2); - an `old` text that is the tail of a line; - a versioned entry indexed without `doc_health`, where a revisionless one still fails on it. Under a global `commit.gpgsign=true`, `tests/test_protected_suite_check.py` read 16 passed and 19 errors before its fixture disabled signing, and 37 passed after. ## For the tasks that follow - **T061** (stacked on this branch): - F5.2's five `validation_launch` reds above are its to clear; - it removes `tests/test_snapshot.py`'s exclusion entry, next in the exclusion file's single-writer chain after this PR; - it is next in the `pyproject.toml` pin's single-writer order. - **T062.** Landed (openDox#16 → `d5098297`). The pin names its commit, `047bb4fa` (see the top). - **T063.** F5.2 whole runs again there. Ruling 6's three `test_session_snapshot.py` cases stay open for F5.2 whole. - **T064 (openxFactory):** - the one host line, `openxdox.projection_contributions.register()` in `scripts/opendox_host.register_openxfactory()` (ruling 1); - `created:` admissions under `openxdox_code` in `docs/opendox-carve-admissions.yaml` for the files this PR creates: `src/openxdox/projection_contributions.py`, `scripts/protected_suites.py`, `tests/test_projection_contributions.py`, `tests/test_governed_registry_and_writer.py` and `tests/test_protected_suite_check.py`. Also `tests/protected_suite_respellings.yaml`, which #34 created. - **T066.** Unchanged by this PR. openxFactory's facet still has to compose the `values` block. #34's note on a page that fetches no `/capabilities` still stands: this PR serves nothing new there. - **T086.** The ratchet goes from here to (0, 0). The eleven remaining reaches are T084's. ## Review - **Copilot.** It reviewed each head from `f0f7f41c` on. Every thread is answered, and every finding in its overviews is either taken or answered in this body. The code findings were taken: - `c34c0de6`: one-window registry reads, renames, the schema integer, and unsigned fixtures; - `11c02cf4`: single-use entries, malformed keys and edits, and the teardown rule stated; - `62a1b0d4`: the root under the guard, and the seam-assembly docstring; - `e7860056`: missing history is exit 2; - `f70ed5d1`: `write_snapshot`'s refusal order, stated; - `9d315537`: `old` starts a line; - `a1b75f3a`: `doc_health` read only for the sentinel; - `1885aee1`, `f22c73b0`, `0fdd65c1` and `4feb8009`: the floors. - `aa0a2c5d`: after the re-pin, Copilot's review at `25414afc` found that a refused registration dropped the unread defaults it had replaced, instead of giving them back. That finding was taken. At `4feb8009` its review read *"Changes recommended"*, with **Findings: None**, and gave the gate as its only reason: T055/T062 had not landed and the provisional pin had not been replaced. Both are now done. Its review at `aa0a2c5d` reads *"Needs a closer look"*, with **Findings: None**, and asked for this description to state the final pin and gate, which it now does. Two threads named allow-list entries as missing. They were left on `f0f7f41c`, and the entries were added at `619684c9`; the replies quote the check admitting them. The pin thread is this PR's stated gate. There are 0 unresolved threads, including r4149710491 at `25414afc`. - **SonarCloud.** The first analysis failed the gate on Security Rating C (S8707). It passes from `7815c2da` on, including at `aa0a2c5d`. 🤖 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>
…ps 1–2) (#18) 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`](opensoft/openxFactory#656 (comment)). - **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](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>



Plan 034, task T062, slice P2-D (the openDox root pin, phase 2). The plan is
specs/034-opendox-standalone-operation/tasks.mdat opensoft/openxFactorymain39f19145. This PR realizes box 9.5 (part) of the ratifiedadd-neutral-product-standalone-operability, as T090 steps 1-2.Arc: neutral-product-standalone-operability
5917907106.5901343950). The holder's lander merges; this writer does not.What changes -- THE PIN THIS PR DELIVERS IS
047bb4fa394f3e1bf42466062a67ef18e99f8d6aONE commit (
ef7e83f7, this PR's head) moves exactly two things, as T039 (#13) did:code(gitlink)2d116415159b721b55613fe20a159afc46202d1f047bb4fa394f3e1bf42466062a67ef18e99f8d6acontracts/code-pin.yamlcommit:2d116415159b721b55613fe20a159afc46202d1f047bb4fa394f3e1bf42466062a67ef18e99f8d6acontracts/code-pin.yamldigests.tree_sha256322f8105d15cf01582dae8771fce2cc6ca9120e5b6bca2750898e872cb6a26e297536dbe7454ac062cc8fd3e34fd15a32eee52213f0292042b243f7e5c699a02Diffstat: 2 files, 3 insertions, 3 deletions. The
specleg andcontracts/spec-pin.yamlare untouched.No workflow file moves. No
.github/workflows/*.ymlreferences the code leg by@<sha>. Checked here withgrep -rnE "openDox-code[^ ]*@[0-9a-f]{40}" .github, which findsnothing; the only 40-hex
uses:pin in the tree isactions/create-github-app-token@fee1f7d6...,an unrelated action.
validate-pins.py's own workflow check (WORKFLOW_REF_RE) raises no finding.Dependencies (T062's
After:line) -- ALL LANDEDT062 is
After: T054-T058 (every phase-2 openDox-code landing), T039 (the root pin's single-writer order),and comes after T053's spec pin and bundle in this root.
f7ee3c76; openDox#14 ->52005213(tagdox-v1.1, tag object851a28e9); openDox#15 ->66758438663ac683a691e4e4(mergedAt 2026-09-30T00:32:48Z)8ec08e91(2026-09-30T15:01:12Z)fa140875(2026-09-30T17:12:43Z)75bd8703(2026-09-30T18:19:46Z)a23e4224(2026-09-30T18:28:21Z)047bb4fa(mergedAt 2026-09-30T19:07:35Z)047bb4fa394f3e1bf42466062a67ef18e99f8d6ais openDox-codemain's tip now that T058 has landed(
gh api repos/opensoft/openDox-code/commits/main --jq .shaat this PR's opening), and is the ONLY committhis PR pins. Its first-parent history above the phase-1 pin
2d116415is exactly nine landings, everyphase-2 openDox-code task: T050
dc3765dd(#53), T05186647320(#56), T052fa8862cc(#54), T054, T057,T055 with its follow-up, T056 and T058 (
git log --first-parent 2d116415..047bb4fain thecodesubmodule).2d116415is an ancestor of047bb4fa, so this is an ancestor move.Falsifier
make pinsin the openDox root, at this PR's head (ef7e83f7, pinning047bb4fa):The repo's own
make validate(naming + manifest + lockstep pins) also passes at this head, exit 0:Before the commit, with the gitlink not yet recorded, the same
make pinsreportedFINDING pin-gitlink-mismatch(recorded gitlink2d116415vs pin file047bb4fa), exit 2, with the digestline already
ok. That is the lockstep rule working, and is why the gitlink and the pin file are one commit.The digest, and how it was recomputed independently
97536dbe7454ac062cc8fd3e34fd15a32eee52213f0292042b243f7e5c699a02issorted-ls-tree-r-v1over047bb4fa394f3e1bf42466062a67ef18e99f8d6a(299 records), the definition incontracts/code-pin.yaml's ownheader. Four methods, none of them copied from another, gave the same value:
repo_shape(splitgit ls-tree -r -zon NUL, drop empties, sort bytewise, sha256 of each record plus\n), in thecodesubmodule's own object store97536dbe...9a02, 299 recordsgit ls-tree -r -z <sha> | tr '\0' '\n' | LC_ALL=C sort | sed '/^$/d' | sha256sum97536dbe...9a02scripts/repo_shape.py::tree_digest(Path('code'), <sha>), the functionvalidate-pins.pyrecomputes with97536dbe...9a02gh api repos/opensoft/openDox-code/git/trees/<sha>?recursive=1(not truncated), tree rows dropped,mode type sha TAB pathrows sorted and hashed, no clone involved97536dbe...9a02, 299 recordsSanity check on the method first. Before trusting methods A and B on the new commit, they were run on the
commit the repo already trusts,
2d116415159b721b55613fe20a159afc46202d1f, and both reproduced the existingcontracts/code-pin.yamlvalue322f8105d15cf01582dae8771fce2cc6ca9120e5b6bca2750898e872cb6a26e2exactly(219 records). Only then were they applied to
047bb4fa.Not this PR
contracts/CHANGELOG.mdis not edited. A code-pin move carries no CHANGELOG line: T039: phase 1's openDox root pin -- code d816cf06 -> 2d116415 (T037 landed; plan 034) #13 and every earliercode-leg bump (openDox root: bump code to da8aae96 and spec to 1a216ea4 (Q-L8 (a), BUILD slices 1+2) #5 to openDox root: bump code to d816cf06 (§ 3.5 runtime, § 3.6 creation, § 3.7 FLOOR PART 3, § 5.4 (d)) and spec to 8fe8c4c7 (four of the five § 6 re-homes) #10) changed only the gitlink,
contracts/code-pin.yaml, and, in openDox root: bump code to da8aae96 and spec to 1a216ea4 (Q-L8 (a), BUILD slices 1+2) #5, openDox root: bump code to a99eba03 and spec to a8f5eb73 (§ 4.3 lazy proxy; BUILD slice 1b) #6 and openDox root: bump code to d816cf06 (§ 3.5 runtime, § 3.6 creation, § 3.7 FLOOR PART 3, § 5.4 (d)) and spec to 8fe8c4c7 (four of the five § 6 re-homes) #10, thespec pair too, and the
codeleg carries no contract bytes (contracts/manifest.yaml: "THE CODE LEGCONTRIBUTES NO ENTRY"). The
dox-v1.1section still names2d116415in its bundle table because it describes the bundle at the taggedcommit
52005213, which it still does. One dated line does read differently after this lands: the## Unreleasedbullet dated 2026-09-29 sayscontracts/code-pin.yaml"still pins2d116415". It is a datedsnapshot and is left as written; refreshing it is a holder call, not part of T090's steps 1-2.
dox-v1.1is phase 2's one bundle (T090), and thedox-v1.1tag is over52005213,untouched.
specleg,contracts/spec-pin.yaml,contracts/manifest.yaml, and every workflow file are untouched.After: T062) movespyproject.toml'sopendox @to this same openDox-code commit (T090 step 3), and T064 (T090 steps 5-6) moves the openXdox root to T061's
commit and to this PR's root commit, and openxFactory's pin pairs with them.
Lane: openxfactory-4 (openXfactory-4-openDox_extraction)
🤖 Generated with Claude Code
Summary by Sourcery
Update the openDox root to pin the completed phase-2 code leg at commit 047bb4fa.
Enhancements:
Tests: