Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9644f33
fix(coordination): bind shadow capture and recovery to durable lineages
wchwawa Sep 6, 2026
e7ce3fd
test(coordination): qualify shadow crashes, writers, and installed pa…
wchwawa Sep 6, 2026
0415a67
docs(coordination): explain bounded qualification and recoverable rol…
wchwawa Sep 6, 2026
08b9c0d
fix(coordination): make validation inputs and ordering explicit
wchwawa Sep 6, 2026
6bbc06c
ci(coordination): lock safe Stage 2C validation inputs
wchwawa Sep 6, 2026
9f1fecf
fix(coordination): fence native Todo updates during management
wchwawa Sep 6, 2026
eb0b599
fix(coordination): retain verified commits when cleanup fails
wchwawa Sep 6, 2026
d64c271
fix(coordination): protect declared sources across goal overrides
wchwawa Sep 6, 2026
da75710
fix(coordination): bind management replay to its operation evidence
wchwawa Sep 6, 2026
c476418
ci(testing): use a pytest-compatible sharding dependency
wchwawa Sep 6, 2026
0c1c4a3
test(coordination): qualify cleanup and cross-goal regressions
wchwawa Sep 6, 2026
8863bfb
test(coordination): refresh the manifest hash mutation locator
wchwawa Sep 6, 2026
a3980a6
test(coordination): remove unused rebased import
wchwawa Sep 6, 2026
b8176a3
test(coordination): reproduce cursor and caller review boundaries
wchwawa Sep 7, 2026
126eb84
fix(coordination): preserve applied cursor digests across no-op prefixes
wchwawa Sep 7, 2026
963e44e
fix(cli): keep rollout evidence on the registry runtime root
wchwawa Sep 7, 2026
54aae58
test(coordination): retain review counterexamples and retirement gates
wchwawa Sep 7, 2026
a48c632
refactor(coordination): own captured primary persistence once
wchwawa Sep 7, 2026
ee1b172
test(coordination): recognize rewritten assertion failures
wchwawa Sep 7, 2026
2118020
Merge origin/main into codex/stage2c-correctness-rollback
wchwawa Sep 7, 2026
11cde6c
fix(coordination): render the fence remediation at the writer adapter…
wchwawa Sep 7, 2026
4ee4ce5
fix(work-items): classify a fenced task-lease write as a typed valida…
wchwawa Sep 7, 2026
ac07b2d
fix(cli): keep envelope keys ahead of typed exception payloads
wchwawa Sep 7, 2026
0ebc704
test(coordination): pin fenced sibling-caller parity across native an…
wchwawa Sep 7, 2026
a096904
test(coordination): reject fence remediation, envelope, and settlemen…
wchwawa Sep 7, 2026
6bd6d88
docs(coordination): state the fenced write response contract and its …
wchwawa Sep 7, 2026
1d58bc9
chore(cli): drop two unused runtime shadow imports
wchwawa Sep 7, 2026
1c1ce9e
Merge origin/main into codex/stage2c-correctness-rollback
wchwawa Sep 7, 2026
507b9f1
Revert "chore(cli): drop two unused runtime shadow imports"
wchwawa Sep 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 65 additions & 1 deletion .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ jobs:
# Without timing history least_duration alternates equal-weight tests.
# Each runner retains the measured two-worker pool.
run: >-
python -m pytest -q -n 2
python -m pytest -q -n 2 -m "not stage2c_e2e"
--splits 2 --group ${{ matrix.shard }}
--splitting-algorithm least_duration
--durations=25 --durations-min=1
Expand Down Expand Up @@ -176,6 +176,70 @@ jobs:
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

stage2c-correctness-e2e:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
with:
python-version: "3.11"
cache: pip
cache-dependency-path: tests/requirements-stage2c-linux-py311.txt
- uses: actions/setup-node@v6
with:
node-version: "22.6"
cache: npm
- name: Install locked test and package build tools
run: |
python -m pip install --disable-pip-version-check --require-hashes --only-binary=:all: -r tests/requirements-stage2c-linux-py311.txt
npm ci --ignore-scripts
- name: Build and verify the checked-out source package
run: |
python -m build --no-isolation --wheel --outdir .local/stage2c-source-install
python - <<'PYTHON'
import hashlib
from pathlib import Path

directory = Path(".local/stage2c-source-install").resolve()
wheels = list(directory.glob("*.whl"))
if len(wheels) != 1:
raise SystemExit("Expected exactly one wheel from the checked-out source")
wheel = wheels[0]
digest = hashlib.sha256(wheel.read_bytes()).hexdigest()
(directory / "requirements.txt").write_text(
f"loopx @ {wheel.as_uri()} --hash=sha256:{digest}\n", encoding="utf-8"
)
PYTHON
python -m pip install --disable-pip-version-check --require-hashes --no-deps --no-index -r .local/stage2c-source-install/requirements.txt
python -m pip check
# Remove the generated source copy before pytest's normal discovery.
python -c "import shutil; shutil.rmtree('build')"
- name: Qualify real CLI, mixed writers, process death, and recovery
env:
LOOPX_SHADOW_COMPARISON_OUTPUT: .local/stage2c-observables
run: python -m pytest -q -m stage2c_e2e --junitxml=stage2c-e2e.xml
- name: Reject deliberate correctness regressions
run: python examples/shared-goal-authority-e2e/mutants.py --output .local/stage2c-mutants
- name: Build independently installed distributions
run: python -m build --no-isolation
- name: Qualify wheel outside the repository
run: python examples/shared-goal-authority-e2e/installed.py --artifact dist/*.whl --report-json installed-wheel.json
- name: Qualify sdist outside the repository
run: python examples/shared-goal-authority-e2e/installed.py --artifact dist/*.tar.gz --report-json installed-sdist.json
- name: Retain bounded acceptance evidence
if: always()
uses: actions/upload-artifact@v7
with:
name: stage2c-correctness-evidence
include-hidden-files: true
path: |
stage2c-e2e.xml
.local/stage2c-observables/
installed-wheel.json
installed-sdist.json
.local/stage2c-mutants/

windows-powershell:
runs-on: windows-latest
timeout-minutes: 20
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2268,9 +2268,14 @@ the unresolved gates remain prerequisites for a real promotion.
writer fence bound to that revision; provider-first `mutate` and
`todo_read` that never fall back to Markdown.
- The fence integration: every Python Todo mutation and every native task-lease
acquire, renew, transfer, and release checks the durable fence while holding
its own lock; an absent fence costs no runtime call; a present, unreadable,
or invalid fence fails closed.
acquire, renew, transfer, release, verify, and committed releasing
fence-close checks the durable fence while holding its own lock; an absent
fence costs no runtime call; a present, unreadable, or invalid fence fails
closed. A fenced write is rejected before its first side effect as a
validation-stage `permission_denied` with no receipt; the shared check owns
only the typed reason and the fence binding facts, and each caller adapter
renders one provider-neutral remediation from them and carries the check
result under `write_check`.
- The complete Todo read model: `loopx_todo_canonical_read_record_v0` publishes
a versioned field manifest, and the TypeScript projection rejects a
replacement that drops fields already present on a stored record.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1799,8 +1799,11 @@ authority 语义与各 provider 的物理 retention 策略。本文档不实现
writer fence 的 `coordination.local_authority.promote`;永不回退到 Markdown 的
provider-first `mutate` 与 `todo_read`。
- fence 集成:每个 Python Todo mutation 与每个 native task-lease
acquire/renew/transfer/release 都在自己的锁内检查持久 fence;fence 不存在时零运行时
调用;fence 存在但不可读或无效时 fail closed。
acquire/renew/transfer/release/verify 以及已提交的释放型 fence-close 都在自己的锁内
检查持久 fence;fence 不存在时零运行时调用;fence 存在但不可读或无效时 fail closed。
被 fence 拒绝的写在第一个副作用之前以 validation 阶段的 `permission_denied`
返回且不产生回执;共享检查只拥有类型化原因与 fence 绑定事实,各调用方 adapter
据此渲染同一条 provider 中立的 remediation,并把检查结果放在 `write_check` 下携带。
- 完整 Todo read model:`loopx_todo_canonical_read_record_v0` 发布带版本字段 manifest;
TypeScript projection 拒绝 replacement 丢弃既有记录中已经存在的字段。

Expand Down
50 changes: 30 additions & 20 deletions examples/shared-goal-authority-e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,23 +84,33 @@ confined to the `bindings` block nulls every binding, marks
`summary.privacy_violations`, which no flag relaxes. Evidence therefore
carries counters, cursors, outcome tokens, and sha256 prefixes only.

## Test seams later PRs must provide

The pending `s2c2.*` rows will be implemented against these seams; a Stage 2C
parity PR that does not expose them cannot be ladder-verified:

- a drain lock file at `<runtime>/authority-shadow/outbox/<goal>/drain` so the
ladder can hold the drain window with `loopx.file_lock.exclusive_file_lock`
exactly as it holds `<runtime>/authority-shadow/file/<goal>/observation`
today, then SIGKILL a writer before or during drain;
- one file per outbox entry under `<runtime>/authority-shadow/outbox/<goal>/`
with a prepared-then-committed marker, so pending entries are countable and
a rollback with pending entries is observable from disk;
- `drain` and `verify` product commands that emit JSON with `drained_count`,
`cursor_before`, `cursor_after`, `parity_verdict`, and the source and
candidate digests, so parity-equal and foreign-edit rows can assert on
typed fields rather than prose;
- the same commands must resolve the runtime root the way `todo` and
`task-lease` do (`effective_runtime_root`), so the one-lineage guarantee that
`s2c1.dual_runtime_root_consistency` proves for the observation hooks also
holds for drain and verify.
## Bounded outbox correctness and the pending ladder

The independently runnable [correctness suite](correctness.md) covers the
`file_outbox_v1` capture lineage, strict cursor recovery, mixed writers,
source fences, and recoverable bootstrap/rollback. It uses real CLI and native
processes, the production `FileAuthorityStore`, and process death at persistence
boundaries. [Installed-package E2E](installed.py) repeats the public lifecycle
outside the checkout for both wheel and sdist. [Negative controls](mutants.py)
deliberately remove correctness checks in disposable source copies.

These checks do not change the nine pending `s2c2.*` ladder declarations above.
Sustained production parity, the migration/growth gates, and promotion remain
separate obligations. A bounded qualification result reports
`sustained_parity_verdict=not_evaluated`.

Future ladder rows must use the actual product interfaces:

- `authority-shadow drain` for receipt-verified replay and cursor recovery;
- `coordination-shadow inspect / qualify / read-candidate` for comparison,
bounded historical qualification, and a qualified read from that same head;
- `coordination-shadow rollback` with an exact revision or unfinished bootstrap
operation selector, followed by explicit rebootstrap;
- the stable management lock outside the goal outbox for scheduling a management
boundary. Rollback moves the entire goal outbox, so a lock inside that directory
cannot coordinate it. The tests retain scheduling-only barriers around real
persistence calls rather than depending on the retired drain lock.

There is no `verify` command or generic `reset`. The independent v0 observation
store and its runtime-root override behavior retain their original scope; its
historical evidence is not an outbox qualification receipt.
Loading