Skip to content

fix(vc-canary): fleet substrate doctrine + strict merge-catalog + legacy units alias - #65

Open
div0-space wants to merge 36 commits into
mainfrom
fix/canary-fleet-doctrine
Open

fix(vc-canary): fleet substrate doctrine + strict merge-catalog + legacy units alias#65
div0-space wants to merge 36 commits into
mainfrom
fix/canary-fleet-doctrine

Conversation

@div0-space

Copy link
Copy Markdown
Member

Two layers on one branch (field findings from the first live canary on loctree-suite, 2026-08-20):

  • b568a66 (codex): strict-default plugin validation in merge-catalog, plugins shell/toml/typescript/javascript, contract tests
  • 094a831 (claude): FLEET substrate rules (N>1 ⇒ worktrees, single-thread integrator, parent-model parity, per-scope scratchpad), SENSE scale-adaptive split + explicit waves, FINDINGS timing rule, agent brief substrate block + return envelope + FENCE (generated/SRI/vendored), CLI legacy 'units' alias with loud warning + regression test (5/5 green)

Note: this branch previously existed on origin and was deleted unmerged by an unknown action — re-pushed from the local worktree, content verified intact.

…TH, review polish

Copilot review threads on PR #54:
- DEFAULT_SERVER was a tailnet address on the leptos reload port
  (100.82.232.70:3025) baked into the shipped binary; now the canonical
  product origin 127.0.0.1:3024 (server_config DEFAULT_BIND_HOST/PORT,
  vc-server DEFAULT_ADDR). VC_SERVER_URL / --server still route to any
  remote or tailnet server — an operator choice, not a compiled-in host
- help text, snapshot and contract tests follow the same default
- fetch_state parses the state envelope once (runs_from_envelope)
- transcript pane: server failures read "server error: …", not "donor: …"
- transcript tail rendering: plain slice of the last 40 lines
- memory.rs: aicx runs with a sanitized PATH (absolute, non-empty entries;
  system fallback) so an implicit-cwd lookup can never pick a stray aicx
- pre-commit: `--` after semgrep args so a staged path starting with `-`
  is always a target, never a flag
- docs: AGENT_OPS + INSTALLED_RUNTIME_CAPSULE state the real worker host
  token ({label}-{short8}-w, WORKER_HOST_SUFFIX) instead of `-workers`
- cargo test 133 passed; spawn worker tests 6 passed; semgrep accepts `--`
Authored-By: claude <agents@vetcoders.io>

session_id: dacccf9f-b20b-41b7-9a72-ec9edc38c73a

time: 2026-08-18T13:47:49+02:00

runtime: interactive
…thread commit

- ruff wrapped the resume-help assertion; prettier had de-indented a list item
  whose code span broke across lines — rephrased so the span stays on one line
Authored-By: claude <agents@vetcoders.io>

session_id: dacccf9f-b20b-41b7-9a72-ec9edc38c73a

time: 2026-08-18T13:48:35+02:00

runtime: interactive
- make release leaves a prunable ghost worktree entry (snapshot2, 2026-08-11): reap on success, prune in trap, contract test
- distribution payload must be symlink-free (3.7.0 shipped 4 symlink entries incl. a stray HOME pointer); fold in-repo aliases into the same cut
- vibecrafted_core/__init__.py barrel drives every non-breaking cycle in the loctree audit; own wave, full gates

Authored-By: claude <agents@vetcoders.io>
session_id: e7734be6-36b7-4e62-a2b2-0af69f9d32e2
time: 2026-08-18T14:20:40+02:00
runtime: interactive
…1.1 release-worktree item

- docs/ROADMAP_4.2.0.md: repo-facing summary of the 9-cut plan (W0 acceptance, W1 release/install seams, W2 Workspaces/app, W3 core imports); plan package lives under ~/.vibecrafted/artifacts/vetcoders/vibecrafted/2026_0818/plans/roadmap-4.2.0/
- docs/ROADMAP_4.1.1.md: item 1 reframed from 'make release leaves a ghost worktree' to 'dirty donors are a release feature' after falsification (no script ever ran git worktree add; the ghost was a manual workaround)

Authored-By: claude <agents@vetcoders.io>
session_id: e7734be6-36b7-4e62-a2b2-0af69f9d32e2
time: 2026-08-18T14:34:56+02:00
runtime: interactive
- aliases were already removed in 4d1f1d1 (#47); W1-a becomes the symlink-free regression guard + Windows-clone smoke (stabilize)

Authored-By: claude <agents@vetcoders.io>
session_id: e7734be6-36b7-4e62-a2b2-0af69f9d32e2
time: 2026-08-18T14:46:07+02:00
runtime: interactive
…r/AUTONOMY.md

- branch pushes and PR creation are the supervisor's; merge into trunk, deploys and host installs remain operator buttons

Authored-By: claude <agents@vetcoders.io>
session_id: e7734be6-36b7-4e62-a2b2-0af69f9d32e2
time: 2026-08-18T14:48:21+02:00
runtime: interactive
…fresh clone

- add tests/tui/test_repo_symlink_free.py: no tracked mode 120000 entry, the
  five historical alias paths stay regular files/dirs or absent, and a
  core.symlinks=false clone (the Windows default) still runs both entrypoints
- fix docs/install.sh: it exec'd ../install.sh directly, but the repository
  file carries no executable bit by design (stated in
  scripts/build-portable-release.sh:86-88), so the shim died with 126 on every
  fresh clone; it now execs bash explicitly, matching the packer contract
- roadmap 4.2.0 cut W1-a: the guard #47 never shipped with the alias removal

Authored-By: claude <agents@vetcoders.io>
session_id: 3da2a070-904b-4d8c-9e40-d3a94d10e3fa
time: 2026-08-18T15:12:00+02:00
runtime: worker
… hand-rolling worktrees

- add scripts/lib/donor-snapshot.sh: detached worktree at each donor HEAD plus
  a reaper that goes through git worktree remove --force and prune, so the
  ghost registration of 2026-08-11 cannot happen again
- add --snapshot-donors to scripts/build-vibecrafted-release.sh; the flag loop
  replaces the single-argument case so it composes with the mode flags, and the
  snapshots are materialised inside build_product so --notarize-only never
  touches a donor
- fold donor_snapshot_reap into the release cleanup trap
- fix scripts/lib/keychain-session.sh trap chaining: _ks_trap_cleanup returns
  the triggering status on purpose, and under set -e that non-zero return tore
  the shell down before the caller's chained handler ran; measured on a real
  failed release, which skipped its own reaper and left both registrations
- resolve donor roots with canonical_dir: the remap prefixes were built as
  "$REPO_ROOT/../vc-frame", and a prefix carrying .. never matches textually,
  which is why the shipped 4.1.0 binaries carry the living checkout path while
  /usr/src/vc-frame and /usr/src/vc-terminal appear in none of them
- add tests/tui/test_donor_snapshot.py: real scratch repos, dirty donor, trap
  path, ghost reclaim, and the subshell regression that the walk-around caught
- pass RELEASE_FLAGS through the Makefile release targets; document the flag,
  the cold rebuild cost and the correct worktree-count check

Authored-By: claude <agents@vetcoders.io>
session_id: 3da2a070-904b-4d8c-9e40-d3a94d10e3fa
time: 2026-08-18T15:26:00+02:00
runtime: worker
… against drift

- assert the framework install.ps1 and vibecrafted-io/site/public/install.ps1
  are byte-identical when the site repo is checked out beside this one
- the 404 on https://vibecrafted.io/install.ps1 is not a pipeline limit: the
  site repo's deploy branch (origin/main, 2026-04-14) never received the
  2026-08-14 commit that added the asset, and /install.sh answers 200
- roadmap 4.2.0 cut W1-c; serving still needs an operator merge and deploy

Authored-By: claude <agents@vetcoders.io>
session_id: 3da2a070-904b-4d8c-9e40-d3a94d10e3fa
time: 2026-08-18T15:40:00+02:00
runtime: worker
… not through the barrel

- __init__.py __getattr__ imported its lazy modules with `from . import X`,
  and `.` is this very file, so the importer graph recorded a structural
  self-cycle on the package barrel; the absolute form names the owning module
- run_triage.py and vc_frame_delivery.py bound a sibling module object the
  same way, which put the barrel in the middle of three diamond cycles
- runtime behaviour is unchanged: the package still initialises before any
  submodule, and the lazy exports stay lazy; what changes is that the graph
  now names the module that actually owns each symbol
- measured with loct on this branch: cycles 0 breaking / 1 structural /
  3 diamond / 4 total before, 0 / 0 / 0 / 0 after; health 74 to 80
- gates: test_package_api_contract.py untouched and green (103 passed with
  doctor and control_plane), mypy clean on all three, semgrep clean, and
  `import vibecrafted_core, vibecrafted_acp.server` still resolves

Authored-By: claude <agents@vetcoders.io>
session_id: 3da2a070-904b-4d8c-9e40-d3a94d10e3fa
time: 2026-08-18T15:56:00+02:00
runtime: worker
…the formatter

- the previous commit spelled the lazy imports `import vibecrafted_core.X as X`
  and ruff PLR0402 rewrote every one of them back into
  `from vibecrafted_core import X` inside the pre-commit hook, which is the
  barrel again; measured right after: structural cycles back to 1, health 80
  down to 78
- use the bare dotted form `import vibecrafted_core.X` plus an attribute read,
  which ruff leaves alone; re-measured 0 breaking / 0 structural / 0 diamond
  and health back to 80, with `ruff check` and `ruff format --check` clean
- lazy exports, package API contract (39 passed) and mypy all unchanged

Authored-By: claude <agents@vetcoders.io>
session_id: 3da2a070-904b-4d8c-9e40-d3a94d10e3fa
time: 2026-08-18T16:03:00+02:00
runtime: worker
…measured

- add the landed-SHA table for the nine 4.2.0 cuts with their real states
- record the seven findings that changed the plan: the fresh-clone exit 126,
  the donor remap prefixes that never matched, the trap chain that dropped the
  caller's cleanup, vibecrafted.io still serving 3.7.0, the answered menu
  question, the missing session-manager permissions, and the five tests that
  were already red

Authored-By: claude <agents@vetcoders.io>
session_id: 3da2a070-904b-4d8c-9e40-d3a94d10e3fa
time: 2026-08-18T16:20:00+02:00
runtime: worker
…d host

Review P1-01 said the `.cargo/registry` leak comes from prebuilt WASM blobs.
Measuring the shipped Vibecrafted_4.1.0-20260817-237d2814.dmg found FIVE
producers, of which `--remap-path-prefix` reaches exactly one:

- Contents/Helpers/vc-frame — 411x $HOME, from git-tracked assets/plugins/*.wasm
  pulled in by include_bytes! while `make release-binary` builds --no-plugins
- Contents/MacOS/Vibecrafted — 21x $HOME/.cargo/.../ring-0.17.14/crypto/...,
  emitted by cc-rs, which reads CFLAGS and not RUSTFLAGS
- Contents/MacOS/Vibecrafted — 51x the checkout root, from Swift sources and
  xcodebuild DerivedData intermediates
- runtime/python/lib/python3.12/_sysconfigdata__darwin_darwin.py — 27x the
  ephemeral uv seed directory
- runtime/python-site/bin/jsonschema — a shebang naming that same seed dir; not
  only a leak, a script that cannot run anywhere but this laptop

Five producers, five levers, so the primary defence is producer-agnostic:

- scripts/payload_hygiene.py streams the finished payload and refuses any
  build-host literal. No allowlist. 2955 files in 1.7s.
- both release channels gate before they sign or publish; `make payload-hygiene
  ARTIFACT=<...>` asks the same question of artifacts already on disk
- the first standalone run missed 277 leaks in the bundled alacritty because it
  did not know the donors; the entry point now resolves them, and a test pins it

Producers closed, with measurements:

- plugins rebuilt inside the donor snapshot under the release remaps: all 14
  blobs go 276 -> 0 occurrences of $HOME, 14 -> 0 of the checkout root. Only
  ever against a snapshot, never the living donor; the snapshot's resulting
  dirty set is exactly zellij-utils/assets/plugins/, which is the whole of the
  new require_clean_repo allowance
- remap order reversed to broadest-first: rustc applies the LAST match, so the
  trailing $HOME entry would have shadowed every specific root on any host
  whose checkout lives under $HOME. Duplicate donor pair dropped
- CFLAGS/CXXFLAGS get -ffile-prefix-map; xcodebuild gets -debug-prefix-map
- python-site/bin deleted, interpreter seed path normalised
- default_command_deck and find_tray_icon no longer probe CARGO_MANIFEST_DIR in
  release builds. That path EXISTS on the build host, so the shipped binary
  preferred the developer's checkout on the one machine the release gets walked
  around on
- five tracked files carried the operator's real checkout into the portable
  tarball verbatim; a host-independent test now guards the whole tree

Gates: unified-product-contract-gate green (606 passed/18 skipped, 83 passed/1
skipped, self-test PASS); 32 release+hygiene contract tests; clippy --workspace
--all-targets -D warnings clean (fixed a pre-existing derivable_impls red);
cargo test --workspace green; shellcheck and semgrep clean.

Not verified: the Swift and cc-rs prefix maps need a full signed release to
confirm. The gate is what makes that non-optional — the next release fails
loudly if they did not work.

Authored-By: claude <agents@vetcoders.io>
session_id: 0658cbd4-0648-48d5-af3e-f24fcb6a3e54
time: 2026-08-18T16:48:32+02:00
runtime: worker
Review P1-02/P2-02/P2-03/P2-04/P2-05. Each of these guarded something real
while being structurally unable to see it break.

P1-02 — the keychain regression suite ran every child with `set -uo pipefail`,
no `-e`. The bug it exists to catch (`_ks_trap_cleanup` returns the triggering
status, and only under `set -e` does that tear the shell down inside the trap
before the caller's chained handler) cannot occur without `-e`. Twenty green
cases; the bug shipped anyway and every failed release silently skipped its
caller's cleanup. `run_child` now uses `set -euo pipefail` — all 61 existing
cases stay green, which is the point: the suite was blind, not wrong — and two
cases are added for the cell that was missing, a chained caller handler AND a
non-zero exit, on both the EXIT and INT arms. Mutation-checked: reverting the
`|| true` from cd13e1c turns exactly one case red, the new one. 66 passed.

P2-02 — the 0-cycles invariant was defended by a code comment, and the repo's
own formatter had already reverted it once inside the pre-commit hook.
test_barrel_import_direction.py parses the AST and refuses `from . import X` /
`from vibecrafted_core import X` for any submodule X, plus the alias form
PLR0402 rewrites back into it. Host-independent, no loctree binary needed.
Mutation-checked: reproducing the formatter's rewrite turns it red at the exact
line, and `loct audit` agrees (structural 1, node __init__.py).

P2-03 — the install.ps1 parity guard skipped everywhere except this laptop.
The digest is now pinned as a constant, so editing the file forces a deliberate
bump, and that bump is the reminder to move the served copy. The cross-repo
comparison stays as an opportunistic extra.

P2-04 — test_dashboard_subcommand was red on the release machine and green
everywhere else. Redirecting HOME is not enough: the launcher resolves the
frontier config under $XDG_CONFIG_HOME, which os.environ.copy() carried in, and
~/.config/vetcoders/frontier/vc-frame EXISTS here — so the launcher preferred
the operator's layout over the repo-owned one under test. Now isolated, here
and in the sibling start-subcommand case. Red -> green.

P2-05 — the review's diagnosis does not survive measurement. VIBECRAFTED_HOME
is already redirected to tmp_path, and the newest rese-* run in the operator's
real control plane is from 2026-08-13, not from any test run. The three reds
are a genuine product hang: the dispatcher blocks in wait4 and its
workflow_runtime research child blocks in the asyncio kevent loop, forever, with
no timeout. Both were reparented to init and alive six minutes later; SIGTERM
to the group took only the dispatcher.

What is fixed here is the damage, not the hang: the timeout path now reaps the
pgid this run recorded in its own meta, and the failure says how many it
reaped. Measured: 0 orphans after a full run, was 6. The hang itself is a
supervisor cut and is reported, not smuggled in.

Also canonicalises the tests' VIBECRAFTED_HOME. pytest's tmp_path happens to be
canonical on this host, so it is defence rather than the fix — reproduced under
/tmp, where the /private symlink makes run_mutation's TOCTOU guard refuse every
launch, and the caller sees only "did not settle".

Gates: keychain 66 passed; 130 passed across release-contract, payload-hygiene
and launcher suites; 42 passed in vibecrafted-core (separate run — the tui and
core conftests collide in one invocation); ruff and shellcheck clean.

Authored-By: claude <agents@vetcoders.io>
session_id: 0658cbd4-0648-48d5-af3e-f24fcb6a3e54
time: 2026-08-18T17:06:00+02:00
runtime: worker
…nup first, argv-safe flags

Review P3-02, P3-03, P3-04, P3-06, and a correction to my own record.

CORRECTION FIRST. The commit message for 85cebab reports the unified product
contract gate as green. That gate run predated the RUSTFLAGS array edit in the
same commit, and against the actual tree it was RED:
test_unified_app_contract.py::test_unified_release_has_one_top_level_owner pins
the literal "--remap-path-prefix=$HOME=/usr/src/operator-home", which no longer
exists as one string now that the remaps are built from PATH_REMAPS. The
contract is updated here to the array form (the invariant it was guarding —
that $HOME is remapped — is unchanged and now also pins the ordering), and the
full gate is green on this tree: 606 passed / 18 skipped, 83 passed / 1 skipped,
self-test PASS, exit 0. Gates must be run against the tree being committed, not
an earlier one.

P3-02 — donor_snapshot_create carried a second, unguarded `rm -rf` beside the
carefully guarded one in the reaper. Both live call sites pass a hardcoded
"$REPO_ROOT/build/..." so neither was reachable, but two spellings of the same
dangerous operation, one guarded, is how a guard gets lost. Hoisted into
_donor_snapshot_force_remove: never the donor, never a root, never an empty
word — the last being what an unquoted array expansion would produce by
splitting a record on its tab.

P3-03 — cleanup() releases the host-wide keychain before reaping donors. The
keychain outlives this process and affects every application on the machine; a
stale snapshot directory under build/ is merely untidy. Reaping first meant a
hung `git worktree remove` (an index lock on a busy donor is enough) would
strand the keychain instead. keychain_session_begin also chains its own handler
ahead of this one, so this ordering only decides the case where no signing
certificate was present — which is exactly when it is the only ordering.

P3-04 — the review's description is half wrong and the other half is real.
MEASURED: a `;` in RELEASE_FLAGS lands after `exec` and never runs. Command
substitution does, because zsh evaluates $(...) while building the exec's argv:

  RELEASE_FLAGS='--snapshot-donors $(touch /tmp/proof)'   -> /tmp/proof exists

Through the environment and split with zsh's ${=...} the same value arrives as
four inert argv words. Verified both ways; benign flags still arrive as one
word.

P3-05 declined, with a reason rather than silence. Setting CARGO_TARGET_DIR to
survive the reaper would break vc-frame's own asset producer:
scripts/plugins-parity.zsh hardcodes $REPO/target/wasm32-wasip1/release, and the
builder reads $FRAME_REPO/target/release/. That is a vc-frame change and belongs
to a cut that can verify it there.

P3-06 — docs/ROADMAP_4.2.0.md no longer claims the leak is "unexplained"; the
producer table replaces it, W0-a's row says what the portable channel actually
carried, and a workflow-stage section records what was measured and what was
deliberately not verified. RELEASE_CHECKLIST gains the payload gate, the
`make payload-hygiene ARTIFACT=` form, and why --snapshot-donors is the only
mode that ships rebuilt plugins.

Gates: unified-product-contract-gate exit 0 on this tree; 41 passed across
donor-snapshot, release-contract and payload-hygiene; shellcheck and bash -n
clean on both touched shell files; prettier clean on both docs.

Authored-By: claude <agents@vetcoders.io>
session_id: 0658cbd4-0648-48d5-af3e-f24fcb6a3e54
time: 2026-08-18T17:42:00+02:00
runtime: worker
…as a duty

- Classify force, trunk, delete, and tag push as the only git-push hard-stop
- Mandate feature-branch push after authored commits
- Mandate reinstall of daily tooling after real tests on our build
- Keep Mode B worktree workers off remotes

Authored-By: grok <agents@vetcoders.io>
session_id: 01a01296-8ec2-7286-be8a-deb4e9fe02d8
time: 2026-08-18T18:08:47+02:00
runtime: worker
…roof subject, see the workshop above the checkout

marble: three truth-forcing cuts where the runtime looked healthy and was not

- vibecrafted_core/supervisor_async.py: bound stdout SILENCE, not wall-clock.
  The heartbeat loop told "quiet" from "dead" but pulsed identically at 20s and
  at 3h, so a worker blocked in wait4 held the supervisor open forever and the
  finished RunState.STALLED handler was unreachable in production — nothing ever
  passed --timeout. A wall-clock cap would kill a long-but-talking worker, so the
  bound is on the signal the watcher already measures. Resolved inside the
  watcher, not at the caller: a bound that must be threaded is a bound nobody
  arms. New _SilenceTimeout settles through the existing handler and records
  stall_kind=silence|wall_clock so triage never has to guess.
- vibecrafted_core/dispatcher.py: --silence-timeout for explicit override; the
  guarantee does not depend on it being passed.
- vibecrafted_core/lifecycle_delivery.py: the delivery proof kernel could not run
  its own verification subject. The executor scrubs env to _SAFE_ENV_KEYS (right),
  which drops PYTHONPATH (right), but the subject was declared `-m
  vibecrafted_core.lifecycle_delivery` — a module invocation resolved through the
  sys.path just removed. It died ModuleNotFoundError/exit 1, the kernel wrote
  proof.failed, and EVERY run it judged settled `failed` regardless of the
  worker's real outcome. Carry the package location as a contract-declared
  argument instead of trusting ambient state. Fixes a red test on this branch.
- vibecrafted_core/runtime_receipt.py: delete two hardcoded build-host workshop
  absolutes. Source 3 already derives both from the package's own location, so on
  the host where they resolved they were duplicates, and everywhere else they were
  dead entries shipping the operator's disk layout inside a signed artifact.
- scripts/lib/payload-hygiene.sh: the gate forbade the exact checkout, and byte
  matching cannot see a PREFIX of it. Measured on the 4.1.0 portable tarball: 5
  offenders with the checkout, 12 with the workshop one level up. Emit the topmost
  still-host-specific ancestor, stopping before generic roots (/Users, /Volumes)
  so the gate does not fail on every absolute path in the tree.
- tui-agent/src/state.rs, control-core/src/read.rs: inline `mod tests` fixtures
  shipped the workshop path verbatim (the packer excludes tests/ directories, not
  test modules inside a source file). Neutral fixture root.
- docs/{public/_CONTRACT.md,adr/0002-...,runtime/DELIVERY_PROOF_KERNEL_v1.md}:
  placeholders where the literal was illustrative.
- tests: 4 silence-bound cases (incl. armed-without-threading and
  slow-but-talking-is-untouched), 1 scrubbed-subject falsifier, 3 gate cases.
  Each verified capable of failing before the fix — the workshop invariant was
  itself blind on first write (guessed parent.parent, looked one level too deep)
  and now asks the library where the workshop is.

Exposed, deliberately NOT decided (for vc-polarize): docs/adr/ownership-matrix.json
declares `/Volumes/vc-workspace` as a checkout-free-install forbidden pattern,
pinned by tests/test_ownership_contract.py. Two correct rules collide on one
string in one shipping file. Whether that rule names one operator's volume or any
checkout root is a product decision, so it is listed as the single documented
exception rather than settled here.

Gate: pass
Tests: make unified-product-contract-gate 606p/18s + 83p/1s self-test PASS exit 0;
  vibecrafted-core/tests 1604p/12s (4 of 5 residual failures were my own
  `-u PYTHONPATH` harness error, not code; 1 pre-existing and unreachable from
  these files); tests/tui payload+donor+manifest 121p; cargo test -p control-core
  20p + doctests; cargo test -p voc --lib 66p; clippy -D warnings clean on both
  crates; shellcheck clean
Regressions: 0
Round-ID: marb-260818-174027-97393-marbles-L1

Authored-By: claude <agents@vetcoders.io>
session_id: 49f60005-6957-4141-95e6-9ebb60b89b62
time: 2026-08-18T18:09:26+02:00
runtime: headless (vibecrafted 4.1.0+g237d2814)
…t only v7

The wire contract said `workspace_id` *is* UUIDv7. The live catalog says
otherwise: 57 workspaces, 35 v7 and 22 v4 — and this repository's own entry
`bda366e0-519f-45f1-8d10-449058491a94` is version 4. Any reader that took the
contract as a validation rule would drop Vibecrafted from its own dashboard.

The runtime was never wrong. `new_uuid7()` is the single minting point;
`require_uuid()` is the single acceptance chokepoint and is version-agnostic by
construction. Only the prose disagreed — so only the prose moved.

- state the accepted-id rule in `WORKSPACE_IDENTITY.md`: mint v7, accept any
  canonical UUID, never validate/filter/sort on the version, read `created_at`
  for chronology; identity table now says `UUID`, not `UUIDv7`
- carry the same rule in the `workspace_catalog` module docstring
- lock it with two regression tests: a real legacy v4 id walks
  create -> show -> select -> list, and list order is asserted to come from
  `created_at` rather than the id bits
- record the cut, and the three rejected axes, in `docs/ROADMAP_4.2.0.md`

Proof the guard bites: `is_uuid` mutated to demand version 7 turns both new
tests red with `workspace_id must be a canonical UUID`, green again on restore.

Authored-By: claude <agents@vetcoders.io>
session_id: bdb9b31e-e2b8-4e46-b994-a485c5fd3b93
time: 2026-08-18T19:52:15+02:00
runtime: vibecrafted polarize (vc-polarize, polarize-L1)
…t lands, not by its name

`vibecrafted doctor` graded one binary three ways on this host. The launcher
check called `~/.local/bin/vibecrafted` a "checkout/legacy bash deck" and said
"Reinstall so an installed owner wins PATH"; `server_supervisor` read the same
generation out of `active.json` as authoritative for the launchd plist; the
delivery receipt in the very same output listed it `[CLEAN]`.

The cause is two layouts, not two ages. `make install` stages
`tools/vibecrafted-generation-*` behind the `vibecrafted-current` symlink;
`Vibecrafted.app` publishes `releases/<version>/` — a layout
`test_unified_app_contract` already pins — and writes `~/.local/bin` wrappers
that `exec` into it. The check recognised a uv-tool shim and a bash deck whose
*path string* contained `vibecrafted-generation-`, so the shipped app's own
install matched neither and was told to reinstall, which reproduces the exact
layout being rejected.

The repository already stated the correct rule. INSTALLED_RUNTIME_CAPSULE.md's
checkout-free gate says doctor fails "when the public launcher resolves outside
`~/.local/share/vibecrafted`" — containment, not naming. Only the opening
paragraph and the code had drifted, in opposite directions.

- ownership is containment in `$VIBECRAFTED_RUNTIME_HOME`, resolved directly or
  through a wrapper's `exec` target; the target is believed only after
  `is_file()` + `X_OK` + `resolve(strict=True)`, so a wrapper cannot talk its
  way into a root it does not enter
- new cross-check: the reported install identity is compared against the
  `VERSION` of the root the launcher actually enters — a mismatch is a `warn`
  naming both, not a silent `ok` on a generation nothing runs
- capsule doc now states the boundary and both publication channels
- five regression tests: app-shaped wrapper ok, wrapper execing a checkout fail,
  absent exec target fail, version cross-check warns on disagreement and stays
  quiet on agreement
- the cut and its five rejected axes recorded in `docs/ROADMAP_4.2.0.md`

Proof the guards bite: against the pre-cut doctor the app-launcher test fails
`assert 'fail' == 'ok'`; with the cross-check mutated to `elif False` the
version test fails `assert 'ok' == 'warn'`; both green on restore. On the live
host `fail` becomes `ok`, and a previously invisible `warn` now names
`4.1.0+ga7f262d9` reported versus `releases/4.1.0+g237d2814` entered.

Authored-By: claude <agents@vetcoders.io>
session_id: d26717ea-c1b5-49f3-af07-2e9ef38ad5df
time: 2026-08-18T20:14:29+02:00
runtime: vibecrafted polarize (vc-polarize, polarize-L2)
…, name the worktree reach

Resume stopped being a verb someone has to remember. Every init pass now
computes this checkout's unfinished work and carries it into the session.

- `init_resume.py` projects the `n` (needs-attention) settlement bucket onto
  one checkout, classifies each run, and renders the exact command that
  continues it. Three properties are the design: silence when clean (a block
  that always prints is a block agents learn to skip), fail-open (a corrupt
  ledger degrades to an honest UNKNOWN, never bricks init), and the ledger
  decides — this module never re-judges a settlement.
- Guardian-owned runs are reported without a command. Each holds a single
  automatic attempt; a hand resume would burn it.
- Newest first, with the truncated remainder counted out loud. Measured on the
  real control plane: this checkout carries 150 `n` rows, so an unordered list
  would have shown July's oldest five and buried today's work.
- Wired into both init surfaces: `workflow._runtime_prompt` (every pipeline
  launch) and `_vetcoders_compose_init_prompt` (`vibecrafted init <agent>`).
- LIVING_TREE_RULE gains a measured "Reach" section (EN + PL): Mode B is
  finished work in the dispatch plane and unreachable from the daily launcher,
  `workflow.py` carries zero worktree references, and marbles `--count` loops
  sequentially — so concurrency comes from several launches on one checkout,
  not from inside one. Stated so the rule stops implying reach the code lacks.

Gates: 11 new tests green; the wiring assertion goes red when the call is
removed and green when restored. vibecrafted-core suite 1652 passed / 4 failed,
of which 3 are a PYTHONPATH-stripped harness artifact (green with PYTHONPATH
set) and 1 (`test_resume_pack_never_selects_native_even_with_same_agent`) is
recorded pre-existing red in ROADMAP_4.2.0. ruff check + format clean;
shellcheck -x clean on operator.sh.

Authored-By: claude <agents@vetcoders.io>

session_id: 0d94cbe4-48da-4878-bc3f-a8c44d67a283

time: 2026-08-18T20:17:57+02:00

runtime: headless
…ad gate lets 4.2.0 ship itself

- self-ship probe (portable channel from clean 0e26b07) failed on payload-hygiene:
  docs/ROADMAP_4.2.0.md carried /Users/<operator>/... in the plan-root pointer
- pointer rewritten to ~/.vibecrafted/... (same meaning, no host identity)
- evidence: scripts/build-portable-release.sh -> FATAL names the build host in 1 place(s)

Authored-By: claude <agents@vetcoders.io>
session_id: e7734be6-36b7-4e62-a2b2-0af69f9d32e2
time: 2026-08-18T20:30:31+02:00
runtime: claude-code
…ay the runtime stamps it

The LIVE RUNS filter was carrying a twin. A run's workspace is resolved by
`workspace_catalog.resolve_run_workspace_identity`, whose first step is the
exported `VIBECRAFTED_WORKSPACE_ID`. The dashboard resolved its own identity
through `live_dashboard.resolve_workspace_id`, which read only the catalog by
`canonical_root` and never looked at the environment. Two implementations of
one question, free to disagree — and on this host they did.

Measured live while this stage ran: the flight's shell exports
`01a00d7b-3964-77a8-bc53-2f41e4b4e509`, a workspace the catalog roots at a
pytest temp directory that no longer exists; 27 run metas carry a workspace_id
the catalog does not root where the run ran. Opened in this repository the
dashboard computed `bda366e0-…` from the root and showed 1 of 2 live rows,
hiding `pola-260818-192800-88430` — the parent run of the polarize flight
itself — and `scaf-260818-202208-26610`, a Mode B worker in a worktree.

The worktree row settles the axis. A worker's worktree root can never equal its
dispatcher's, so a root-only reader is structurally unable to see a dispatched
worker. `workspace_id` is documented as *not* derived from root; the dashboard
was the surface that had forgotten it.

- one resolution order for every surface: exported `VIBECRAFTED_WORKSPACE_ID`
  first, then the one canonical catalog by `canonical_root` — both arbitrated
  by that catalog, so a bare id is evidence, never identity
- `_active_workspaces` folds the catalog read that both steps share; an
  unusable catalog (absent / unreadable / foreign schema / malformed) still
  resolves to None and the filter still falls back to exact-root identity
- the wire contract now states the order once, names the role boundary after a
  refusal (writers refuse loudly, readers refuse quietly and continue), and
  records that a stale export turns later launches into a hard error
- five regression tests: export honoured over the root lookup, unknown id
  refused, buried id refused, unusable catalog refuses even a valid export, and
  the whole flight — worktree worker included — stays visible
- module docstring stops claiming to be the surface behind the LIVE chip; that
  chip is server-backed in `tui-agent/src/observe.rs`

Proof the guards bite: with the env branch disabled the export test fails
`assert 'ws-rooted-here' == 'ws-exported'` and the flight test fails
`assert [] == ['pola-…', 'scaf-…']`; with the catalog corroboration dropped the
unknown-id and buried-id refusals both fail. Green on restore, no probe residue
in 1167 scanned files. On the live control plane the patched reader takes the
visible rows from 1 to 2 and puts this flight back in its own dashboard.

The census, its liveness rule, and the parity contract with vc-frame's
`vc_live_runs.rs` are untouched.

Authored-By: claude <agents@vetcoders.io>
session_id: b8520be2-e22c-4638-9f3b-3527859d9f98
time: 2026-08-18T20:38:00+02:00
runtime: vibecrafted polarize (vc-polarize, polarize-L3)
… own licence, write down what landed

The DoU audit graded the engineering sound and the outward channel dead. Three
of its four top priorities are operator buttons. These are the parts that are
repository truth, and they were genuinely undone.

- plugin.json declared version 2.0.0 and license Apache-2.0. VERSION reads
  4.1.0 and LICENSE opens with SPDX-License-Identifier: BUSL-1.1. That file is
  listed in ALLOWED_TOP_LEVEL by both install.sh and distribution_manifest.py,
  so the contradiction rides into every distribution archive and lands on every
  installed host directly beside the LICENSE it disagrees with. Last touched
  2026-07-02, when 2.0.0 was still true: stale, not wrong, which is exactly the
  shape a gate exists for. It now carries the version and SPDX identifier it
  ships with, plus the author, homepage and repository the generated
  marketplace manifest already uses.
- tests/tui/test_plugin_manifest_contract.py binds it three ways: version to
  VERSION, license to the SPDX line of LICENSE, and author/homepage/repository
  to build_marketplace_bundle.plugin_manifest, with a third case asserting the
  file really does travel in the distribution. Mutation-checked - restoring the
  pre-cut pair turns the first red with "plugin.json version '2.0.0' !=
  VERSION '4.1.0'", green again on restore.
- CHANGELOG.md carried two bullets under Unreleased against 23 commits of
  landed work. The section now states the 4.2.0 scope across Added / Changed /
  Fixed / Security. It stays Unreleased on purpose: v4.1.0 was never tagged, so
  dating a 4.2.0 heading here would repeat the class of claim this flight
  exists to retire. The release stage promotes it together with the tag.
- ROADMAP_4.2.0.md gains the landed ledger the flight's definition of done asks
  for: every cut mapped to its landing SHAs and to what still stands between it
  and [x], plus the commits carried under the flight without owning a cut.
- SUBMISSION_FORMS.md gains awesome-agent-orchestrators as launch item zero -
  free, no editorial queue, and the one directory where the near-identical
  namesake vibecraft.build is already listed while we are absent. Verified live:
  github.com/andyrewlee/awesome-agent-orchestrators, ~1.2k stars, fork-and-PR
  in a one-line format. The note carries the paste-ready line and the
  prerequisite that a Release must first carry an installable artifact.

Two DoU findings are corrected rather than executed, and the roadmap records
both. P1-8's docs half does not hold for this repository - docs/INSTALL.md
opens with a channel matrix naming the signed DMG, carries a full macOS desktop
section, and documents make app; the zero-hit measurement was of the deployed
site, which is three months stale and lives in vibecrafted-io, so that gap is
the same deploy button as W1-c. P2-10's brand half is declined - "Vetcoders" is
the prevailing form here at 272 occurrences against 6 and is hardcoded in the
bundle manifest, so a rename is an operator branding decision, not a hydration
cut.

The contract tests live in a new file rather than in
tests/tui/test_distribution_manifest.py, where they would naturally belong.
That file carries a pre-existing blocking semgrep finding at line 1249
(trailofbits tarfile-extractall-traversal) against code that is already
mitigated - it asserts no absolute paths and no ".." members before calling
extractall(filter="data"). The staged-only pre-commit scanner therefore refuses
any commit that stages it, and the only in-file remedies are a nosemgrep
silencer or a ruleset change, neither of which is a hydration cut. Reported for
the operator instead of muted.

Gates: tests/tui/test_plugin_manifest_contract.py 3 passed and
tests/tui/test_bundle.py green; ruff check and ruff format clean; prettier
clean; semgrep clean on every staged file; no host path in any changed file.
make unified-product-contract-gate not run - this commit touches neither
vibecrafted_core nor scripts/, so its trigger did not fire.

Authored-By: claude <agents@vetcoders.io>
session_id: 8e31b184-a9da-4471-accc-3dabad047a2f
time: 2026-08-18T21:04:01+02:00
runtime: headless
…it declares

The DoU named the flight's top risk exactly: 4.2.0 could be tagged and fail as
4.0.0 did, because 54a98b2 (runs-on: macos-15) has never run against a real
tag. Release went looking for what else that untested path would hit and found
the next mine on it.

- .github/workflows/release.yml: the final step, "Confirm publication boundary
  for both channels", invoked ripgrep through a `command` lookup, which forces
  a real rg binary on PATH. The GitHub macos-15 image ships no ripgrep.
  Measured 2026-08-18 against actions/runner-images
  images/macos/macos-15-Readme.md: zero occurrences, alongside zero for
  shellcheck, which this same workflow independently confirms by having to brew
  install it before it can lint. In this repository rg exists only inside our
  own container images (Dockerfile:40, vibecrafted-vm/Containerfile:118), never
  on the runner. Under set -euo pipefail that ends the job, so curing xcrun
  would have moved the failure four steps later rather than removing it: every
  test green, every build done, then death on a missing binary. The step
  arrived in ef700e5 (3.7.1) and has never once executed, because every tag
  since died earlier - no amount of "the last release worked" could surface it.
  Both assertions now use POSIX grep. Same patterns, same four files, same
  fail-on-no-match semantics; verified locally to still match on both channels.
- tests/tui/test_release_contract.py: two tests so this cannot come back. The
  first refuses any run: line in the tag gate that calls a binary absent from
  the runner image and not brew installed, and separately requires the
  shellcheck install wherever make check runs - the quieter half, because
  check_shell.py falls back to bash -n, so dropping that install would keep the
  gate green while degrading it from a linter to a syntax check. The second
  pins the boundary step's two patterns and all four files it covers, so
  rewriting the matcher cannot silently shrink what it matches.
- scripts/hooks/pre-push: semgrep now runs under env -u PYTHONPATH -u
  PYTHONHOME, the isolation pre-commit has carried for a while. Reproduced here
  rather than assumed: with the runtime's PYTHONPATH exported, Homebrew
  pysemgrep dies at import with ModuleNotFoundError: No module named
  'rpds.rpds' - the runtime's python-site shadows jsonschema/referencing/rpds.
  The same scan under the wrapper returns rc=0. A security gate that crashes is
  one people learn to --no-verify past.
- templates/hooks/lib/lint-routing.sh: the same isolation for the shipped husky
  template's staged and full semgrep helpers. There the crash is worse-behaved,
  not better - the WARN-mode step counter reports it as a warning, so the gate
  stops gating without anyone noticing.
- docs/RELEASE_CHECKLIST.md section 5 and docs/ROADMAP_4.2.0.md: the gate's real
  run history, both tool gaps, and the plain statement that the next tag is an
  experiment - push v4.1.0 at 27ad70e first, since it is merged, stable,
  already called released by VERSION and CHANGELOG, and has no tag at all.

VERSION stays 4.1.0 and the CHANGELOG stays Unreleased. v4.1.0 has no tag while
both files already call it released; dating a 4.2.0 heading on top of that would
add a third unanchored version claim to a flight whose purpose is retiring that
class of claim.

Mutation evidence, and both first drafts passed for the wrong reason. Restoring
the ripgrep invocation turns the tooling test red naming both offending lines;
removing brew install shellcheck turns it red on the make check allowance. That
second case was green at first: the test read "brew install" out of the raw
workflow text, and the explanatory comment this same cut added to release.yml
contains that phrase. A test that reads a whole file also reads the comments
written about it. Installs are now parsed only out of run: lines.

Gates: make unified-product-contract-gate green in full, run leg by leg because
the composed target exceeds this worker's 120s foreground ceiling. Leg 1, the
eight tui contract files, 606 passed 18 skipped in 478s; leg 2, the four core
distribution files, 88 passed 1 skipped; leg 3, verifier self-test PASS valid=4
negative=2 error_codes=24,27 with both schemas well-formed and the verifier
syntax-clean; leg 4, the wheel leg, fail-closed rc=22 on all three probes from
an installed console script with no walkaround written. make check green over
162 shell files; test_release_contract + test_shell_check 27 passed; ruff,
prettier and semgrep clean on every changed file.

Authored-By: claude <agents@vetcoders.io>
session_id: 30a35af4-bc99-4706-8816-f4864c107f9a
time: 2026-08-18T21:34:00+02:00
runtime: headless
…cally

run.meta.json is a cross-process contract read by the launcher, the startup
watcher, control-plane sync, dashboards and the lifecycle tests while another
process is writing it. Four writers still truncated the file in place, so a
concurrent reader could observe an empty document — the exact JSONDecodeError
flake CI hit in test_generated_launcher_walks_full_lifecycle.

- meta.sh: spawn_update_meta_pid, spawn_reap_dead_run and
  spawn_mark_unknown_liveness now publish via tmp + os.replace, the same
  pattern spawn_mark_meta_running already used for the same stated reason
- spawn.py: _write_meta (write-meta / finish-meta / finalize) publishes via
  tmp + os.replace as well
- tests/tui/test_meta_lifecycle.py: contract test pins the invariant — no
  in-place open("w") on meta, every live-state writer carries os.replace

Authored-By: claude <agents@vetcoders.io>

session_id: 9443b071-4b21-48d7-a0d7-d9d1f4b107e5

time: 2026-08-18T23:01:33+02:00

runtime: interactive
…e line-number gutter

Parity projection of vc-frame 7332fb7a2: the Composer and the scrollback
viewer stop rendering line numbers, because a mouse selection copies rendered
cells and the gutter rode into every paste. In-editor yanks never carried it.

Authored-By: claude <agents@vetcoders.io>

session_id: 9443b071-4b21-48d7-a0d7-d9d1f4b107e5

time: 2026-08-18T23:25:41+02:00

runtime: interactive
…step, not ink

The new compact-bar chrome paints every second inactive tab with
ribbon_unselected.emphasis_1 as its background ("alternate rows shift the
background one step" — THEMES_GUIDE rhythm doctrine, same as bundled
monochrome). vibecrafted-ivory still carried 55 48 42 (near-black ink) in
that slot from before the doctrine, so light mode rendered alternating
dark chips with dark text on the bone bar.

- emphasis_1: 55 48 42 -> 226 219 205 (one close step from 235 228 215)
- doctrine comment pinned next to the value, mirroring monochrome.kdl

Authored-By: claude <agents@vetcoders.io>

session_id: 193bae84-28e3-499e-b43d-0eb2a74811a0

time: 2026-08-19T00:10:08+02:00

runtime: interactive
… DMG shim chain

The bash deck dispatches on basename $0, but the app installer publishes
env-shims that exec the deck through a shebang — and the kernel rebuilds argv
for #! targets, so the invoked wrapper name never survives the chain.
vc-resume claude --session <id> degraded into vibecrafted claude --session
<id> ("Unknown mode: --session"); vc-dispatch, vc-init, vc-help, vc-justdo,
vc-dashboard and telemetry died the same way.

- AppDelegate.swift: deck-verb wrappers — the shim carries its verb
  (exec '<deck>' resume "$@"), guarded so a real runtime binary of the same
  name always wins; exec -a is not a fix because it cannot cross a shebang
- AppDelegate.swift: the runtime/shell projection into ~/.config/vibecrafted
  refreshes on every install instead of copy-once; the frozen copy shipped a
  parser that predated --run-id while the release already spoke it
- tests/tui/test_keys.py: pins the Swift verb list 1:1 to
  cli.SHELL_WRAPPER_VERBS (minus vc-start, which ships as a real binary)

Audit + operator repair receipt:
~/.vibecrafted/reports/2026-08-19_launcher-identity-audit.md

Authored-By: claude <agents@vetcoders.io>

session_id: 41e20724-e996-4bfe-a82c-3de78e7c691b

time: 2026-08-19T00:18:46+02:00

runtime: interactive
…ng bounded drain

- os.killpg(pgid, 0) raises PermissionError on macOS CI when the group still
  holds members in another security context; the drain loop crashed instead
  of waiting out its 5s deadline
- EPERM means exists-but-unsignalable: keep draining; ESRCH remains the only
  gone signal. Unblocks required check portable (macos-latest) on PR #55

Authored-By: claude <agents@vetcoders.io>

session_id: 92c785f7-2797-4971-b33e-d31d05057aa2

time: 2026-08-19T11:17:35+02:00

runtime: interactive
… requests, not only at tag time

- release.yml's source-gate is tag-only, so v4.1.0 @ 27ad70e was the first
  time in five weeks the core suite met a bare macOS runner: 5 failed /
  1596 passed (3x terminal runtime, KeyError 'env' in the cell launcher,
  resume-pack red). Locally, even under an empty HOME, only 2 of those
  reproduce — the other 4 exist only on the runner
- add core-macos.yml: same checkout/uv/'make test-core' steps as the gate,
  on pull_request (core paths) and workflow_dispatch, pinned actions
- a tag becomes a confirmation of a green PR check instead of an experiment

Authored-By: claude <agents@vetcoders.io>
session_id: e7734be6-36b7-4e62-a2b2-0af69f9d32e2
time: 2026-08-19T13:51:32+02:00
runtime: claude-code
…o a single symlink

- plan_delivery stops wiring two per-file projection farms; ~/.config/vc-frame
  becomes ONE directory symlink at the package-owned generated tree (through
  vibecrafted-current), the frontier twin dissolves on every pass
- owned links drained, STALE files backed up, foreign entries preserved
  (whole-dir displacement is an auditable .stale backup, twin foreigns skipped)
- tests rewritten to the one-home contract + migration test: legacy link farm
  and twin collapse in one pass with zero stray backups

Operator 2026-08-20: jeden config, sekcje zamiast rownoleglych drzew.

Authored-By: claude <agents@vetcoders.io>

session_id: 92c785f7-2797-4971-b33e-d31d05057aa2

time: 2026-08-20T17:13:49+02:00

runtime: interactive
…r-file link channels

- vc-frame:view classifies the view itself: ok=symlink into store/dev,
  warn=legacy real dir (collapsible), fail=dangling/missing
- frontier twin presence is a warn with remediation; absence is the ok state
- operator-scripts + Super/Cmd key contract checked once, through the view

Authored-By: claude <agents@vetcoders.io>

session_id: 92c785f7-2797-4971-b33e-d31d05057aa2

time: 2026-08-20T17:14:05+02:00

runtime: interactive
…ymlink, generated, legacy last

- resolution order everywhere: env pin -> ~/.config/vc-frame (symlink shape
  only) -> generated under vibecrafted-current -> frontier twin (legacy) ->
  real-dir view as last resort until vibecrafted update collapses it
- symlink-shape guard keeps the old rebrand protection: a stale real dir can
  never shadow the product config
- frontier candidate chains stay for starship/atuin sidecars (Phase B)

Authored-By: claude <agents@vetcoders.io>

session_id: 92c785f7-2797-4971-b33e-d31d05057aa2

time: 2026-08-20T17:14:14+02:00

runtime: interactive
…both app surfaces

- launch.rs: resolved_vc_frame_config_dir learns the canonical view and the
  generated tree before falling back to the repo checkout
- AppDelegate: vc-frame productConfig copy-once becomes refresh-every-install
  (same disease and same cure as the shell layer right below it)

Authored-By: claude <agents@vetcoders.io>

session_id: 92c785f7-2797-4971-b33e-d31d05057aa2

time: 2026-08-20T17:14:23+02:00

runtime: interactive
Loads every language plugin before catalog settlement and fails closed on the first missing required field, invalid kind, or unmatched source file. Adds shell, TypeScript, JavaScript, and TOML contracts with executable regression coverage.

Authored-By: codex <agents@vetcoders.io>

session_id: 01a02083-f82e-76c1-87ca-b0d79ecbca60

time: 2026-08-20T21:01:36+02:00

runtime: headless
…nces — first live run findings

- FLEET: N=1 → Living Tree, N>1 → Fleet Worktrees (Mode B): worktree+commit per scope, single-thread integrator; native subagents inherit the parent model; per-scope scratchpad dir (flat tmp names collided between parallel scopes)
- SENSE: scale-adaptive split when one plane dwarfs the rest (73% of LOC in one crate today); deferred scopes declared as waves in scopes.json
- FINDINGS: only after the fleet settles — loct follow counts drifted 4→9 mid-wave; pin the snapshot fingerprint next to quoted counts
- brief: substrate block replaces the hardcoded Living Tree header; explicit return envelope (top-level key 'catalog'); FENCE for generated / SRI-pinned / vendored artifacts — a comment byte in an SRI-pinned file is an outage, not documentation
- canary_cli: legacy top-level 'units' accepted with a loud stderr warning (today's 8-scope run would have died at merge); +1 regression test, 5/5 green on the b568a66 suite

Builds on b568a66 (codex: strict plugin enforcement). Evidence: loctree-suite wave 1, 2026-08-20 — 8 scopes, 1299 units, commit 788400c0 in Loctree/loctree-suite.

Authored-By: claude <agents@vetcoders.io>
session_id: 760d0c62-f5af-49d7-a8a1-09532f6a9584
time: 2026-08-20T21:26:39+02:00
runtime: interactive
Copilot AI lite review requested due to automatic review settings August 22, 2026 05:57

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Code review skipped — your organization has reached its monthly code review spending cap.

An organization admin can view or raise the cap at claude.ai/admin-settings/claude-code. The cap resets at the start of the next billing period.

Once the cap resets or is raised, reopen this pull request to trigger a review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants