Per-target north star (98a): atomic gate+doctor+persona flip, reading committed target state - #101
Conversation
…ed read (#98) Activate the dormant #99 resolver atomically: the consensus gate's source and Faber's approval source flip together, and the gate reads COMMITTED target state. - manager-review.sh: resolve the north star for the TARGET via ns_resolve, and read its COMMITTED content pinned to the SAME commit the review worktree runs on ($head_commit) — never a free-floating later HEAD (debate GAP). A star that exists only as an uncommitted worktree edit does NOT authorize (UNSET → FAIL); a committed star STILL authorizes even if the worktree copy is deleted/modified. LOCAL star with the fabrica-shipped-default marker → FAIL (placeholder); FABRICA_SELF exempt. - doctor.sh check (h): resolve the target's star via the resolver (consistent with the gate); UNSET → WARN (not FAIL); marker/staleness semantics preserved; notes when the worktree copy differs from HEAD (diagnostic reads the working tree). - Faber approval/logging source flips in the SAME PR: templates/faber-command.md + manager/CLAUDE.md now reference the resolved target (committed) .fabrica/north-star.md, not {{FABRICA_ROOT}}/NORTH_STAR.md (Fabrica-self exception kept). Gate source ≡ approval source. - setup-target-repo.sh: re-add seeding of <target>/.fabrica/north-star.md from the template (idempotent, cwd-slug==target guarded via ns_slug_eq + env -u GH_REPO); --check reports a missing star as drift. - templates/.fabrica/north-star.md: present tense — consumers use it now; marker kept. - Tests: new scripts/test/north-star-gate.test.sh (30 asserts) — both-direction committed test + approval==gate source identity + LOCAL/marker/UNSET + doctor + setup; wired into CI and the required-files manifest. #99 resolver suite stays green (33). Self-modification note: scripts take effect on merge; the /faber command changes only after re-running scripts/install.sh; the persona takes effect on next read. This is the safety-critical atomic flip (gate source ≡ approval source, committed-only) — the rail being preserved, not weakened. Closes #98 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Codex reviewer (cross-vendor, read-only)Reviewed-head: b33b444 Posted verbatim by The manager-review gate rejects valid seeded north-star files because it scans the whole file for the placeholder marker, and setup can also shadow Fabrica-self's root north star. These issues break the core per-target north-star workflow introduced by the patch. Full review comments:
|
Two adversarial passes (Codex review + an attack sweep) found 6 distinct authorization bugs in the per-target north-star gate flip. Fix all six, each with a regression assert; both suites stay green. A. Placeholder check (gate + doctor) — scope the shipped-default marker check to the ACTIVE-entry region (not the whole file: the marker also appears in the template prose, so a whole-file grep wrongly FAILs a correctly-replaced star) AND match it whitespace/case-insensitively (a byte-exact grep let `<!--fabrica-shipped-default-->` / padded / UPPERCASE / tab / reflow-split variants bypass and wrongly AUTHORIZE). New shared helper ns_has_shipped_default_marker / ns_active_region in the lib, used identically by manager-review.sh and doctor.sh (h) so they never disagree. B. [P1 SECURITY] Resolver Fabrica-self identity is now PATH-only. Dropped the slug-based FABRICA_SELF fallback: the slug derives from the attacker-settable git remote URL, so a target pointing origin at Fabrica's slug was authorized against Fabrica's root star (bypassing its own star + the placeholder-FAIL). Kept only the gh-free path check (toplevel == ns_fabrica_root), and gave it PRECEDENCE over the Order-1 LOCAL check so a stray/committed .fabrica/north-star.md in the control-plane checkout can't shadow the root. C. setup-target-repo.sh never seeds .fabrica/north-star.md into the Fabrica control-plane repo itself (path-based detection, same as B); skips with a note. D. doctor.sh guards the resolver `source` so a missing scripts/lib/north-star.sh is reported as a fail: line and the summary still prints (no crash). E. doctor.sh (h) drives its verdict off the COMMITTED star (git cat-file -e HEAD:… + git show HEAD:…), matching what the gate authorizes on; the working-tree copy is a supplementary note. UNSET still WARNs. F. [confused-deputy] manager-review.sh refuses to authorize off a north star in a SEPARATE git repo NESTED inside another git work tree (detected by parent-in- work-tree + a DIFFERENT --git-common-dir, so a legitimate linked worktree is NOT rejected). Tests: +10 resolver asserts (43 total), +18 gate asserts (48 total). CI-green locally: structure check (bash), shellcheck -x -S style, bash -n, both suites. Prompt-sync note: manager-review.sh / doctor.sh / setup-target-repo.sh take effect when re-run; scripts/lib/north-star.sh takes effect when re-sourced by them. No /faber regeneration needed (install.sh unchanged). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Deploying fabrica with
|
| Latest commit: |
71eae3c
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://3c335278.fabrica-6yx.pages.dev |
| Branch Preview URL: | https://issue-98a-atomic-flip.fabrica-6yx.pages.dev |
round-1 — 6 authorization fixes (head
|
Codex reviewer (cross-vendor, read-only)Reviewed-head: 16e59ff Posted verbatim by The patch adds the intended per-target north-star flow, but it has edge cases that can block valid north stars: self runs can ignore a committed root star if the worktree file is absent, and marker detection can false-positive on prose mentions. These are functional gate failures rather than documentation nits. Full review comments:
|
…s (round-2)
Round-1 closed 6 breaks; a Codex re-review + a second attack workflow found 4
residual edges (one a round-1 regression). All 4 preserve the authorization rails.
FIX 1 — FABRICA_SELF off COMMITTED state (ns_resolve): the Order-1 self branch now
keys on `git cat-file -e HEAD:NORTH_STAR.md` (committed existence), not a working-tree
`[ -f ]` stat, so a committed-but-worktree-deleted self star still resolves FABRICA_SELF
and agrees with the gate's `git show HEAD:NORTH_STAR.md`.
FIX 2 — placeholder marker = COMMENT FORM, not a bare token (ns_has_shipped_default_marker):
match the `<!-- … fabrica-shipped-default … -->` HTML-comment form (whitespace/newline/case
tolerant via strip+lowercase, then ERE `<!--[^>]*TOKEN[^<]*-->` with `[^>]`/`[^<]` boundary
guards) instead of a bare token anywhere in the active region. Genuine comment variants
(no-space/padded/UPPER/tab/line-split/interior-text) still match; a delimiter-free PROSE
mention in the active region no longer false-FAILs a valid star.
FIX 3 — case-canonicalize the Fabrica-self path compare (round-1 regression): ns_fabrica_root
now canonicalizes its physical root through git (`git -C <root> rev-parse --show-toplevel`,
falling back to `pwd -P` when not a work tree), so both operands of `toplevel == fabrica_root`
are git-canonical — no false case-only difference on a case-insensitive FS. Fixes both the
resolver's self debate and setup-target-repo.sh's seed guard (shared helper).
FIX 4 — reject a committed SYMLINK north star (ns_committed_is_regular_file, used by the gate's
LOCAL + FABRICA_SELF branches and doctor (h)): before the marker check, assert the committed tree
entry mode is 100644/100755, not 120000. A committed symlink makes `git show` return the link
target-path string, bypassing the marker check; the gate now FAILs ("must be a regular file, not
a symlink") and doctor WARNs.
Tests: +1 regression test per fix in both suites (resolver 50 passed, gate 58 passed; all prior
gate+resolver asserts stay green). CI-green locally: structure check, shellcheck -x -S style,
bash -n, both suites.
Pin-anchor hardening (local HEAD -> origin/HEAD/default-branch) is deferred to #102 (offline/
greenfield tradeoffs). Prompt/doc note: this changes scripts/lib/north-star.sh + the gate/doctor/
setup consumers; live behavior changes only when Faber re-reads these synced artifacts.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Round-2 — 4 residual authorization fixes (Codex re-review + second attack workflow)Head: FIX 1 — FABRICA_SELF off COMMITTED state ( FIX 2 — placeholder marker = COMMENT FORM, not a bare token ( FIX 3 — case-canonicalize the Fabrica-self path compare (round-1 regression; FIX 4 — reject a committed SYMLINK north star (new shared helper Tests (one per fix; all prior asserts stay green)
CI green locally
DeferredThe pin-anchor hardening (pin the gate to Self-modification note: these change |
CI's shellcheck 0.9.0 (ubuntu-latest preinstalled) flags 4 findings under -S style that local 0.11.0 does not. Close the skew: - SC2015 (manager-review.sh:195,196): move `|| true` outside the command substitution onto the assignment, removing the `A && B || C` shape inside the subshell (still errexit-safe). - SC2317 (north-star-resolver.test.sh:186,188): the intentionally-unreachable slug stubs — make the disable version-robust with `SC2317,SC2329` (0.9.0 emits SC2317, 0.11.0 emits SC2329 for the same "appears unreachable"). Verified clean under both shellcheck 0.9.0 (CI-exact `-x -S style` sweep) and 0.11.0. Resolver (50) + gate (58) suites pass; structure check ok. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
CI-red fix: shellcheck 0.9.0 vs local 0.11.0 skew (head CI runs shellcheck 0.9.0 (ubuntu-latest preinstalled); locally we have 0.11.0, which does not surface these — that version gap was the whole bug. Reproduced the 4 CI findings by running shellcheck 0.9.0 directly ( Fixed:
Verified: full 0.9.0 sweep across all Note for coders: local shellcheck 0.11.0 disagrees with CI's 0.9.0 — verify against 0.9.0 (or write version-robust disables covering both code numbers) before declaring shellcheck green. |
Codex reviewer (cross-vendor, read-only)Reviewed-head: 050cb94 Posted verbatim by The new symlink guard breaks documented subdirectory invocations of manager-review.sh, and the active-region scanner can miss the real active placeholder marker when earlier prose contains the same status phrase. These are functional gate issues that should be fixed before considering the patch correct. Full review comments:
|
FIX 1 [P2] — ns_committed_is_regular_file resolves the pathspec from the git
TOP-LEVEL before ls-tree. The helper took dir=$PWD with a ROOT-relative relpath,
so when manager-review.sh runs from a SUBDIRECTORY of the target (documented as
supported) git ls-tree interpreted the pathspec relative to the subdir -> the mode
lookup returned EMPTY for a valid regular committed file -> the round-2 symlink guard
falsely REJECTED the run. Now resolve <dir> to its git top-level first (empty top ->
rc 1, never 'git -C "" ls-tree' which stays in the cwd), so the mode check is correct
from any subdirectory.
FIX 2 [P2] — ns_active_region starts the active region ONLY on a Markdown HEADING
line (^#{1,6}[[:space:]]) that ALSO carries the status:...active marker, not any line.
A prose/front-matter mention of 'status: active' BEFORE the real active heading would
open the region early and end it at the next heading -> the shipped-default marker on
the ACTUAL placeholder heading was never scanned -> placeholder bypass (gate proceeds
against an unreplaced template). The real shipped NORTH_STAR.md / .fabrica/north-star.md
active entries ARE headings, so this matches the shipped format.
Tests: +1 resolver test per fix (subdir pathspec resolution + heading-anchored region;
7 new asserts, 50->57) and +2 gate integration tests per fix (subdir regular star
proceeds / subdir symlink still fails; prose-before-heading still FAILs / single-heading
proceeds; 8 new asserts, 58->66). Two round-1 placeholder fixtures updated to the
heading-form marker that reflects the real shipped template. All 66 gate + 57 resolver
asserts green.
These PRESERVE the authorization rails. shellcheck 0.9.0 (CI's version) clean over all
*.sh (-x -S style); structure check ok; bash -n clean. Prompt/behavior sync: none (this
is gate tooling, not a prompt).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Round-3: 2 precision fixes from the final Codex review, both in FIX 1 [P2] — symlink guard resolves the pathspec from the git top-level ( FIX 2 [P2] — active-region scan starts on a heading line ( Tests (one regression test per fix, plus gate integration):
All 66 gate + 57 resolver asserts green. These preserve the authorization rails (symlink guard, committed read, placeholder-FAIL, PATH-only Fabrica-self identity all intact). Local verification: |
Codex reviewer (cross-vendor, read-only)Reviewed-head: 0429652 Posted verbatim by The resolver can misclassify a Fabrica-self checkout as a normal target when the root north star is missing but a stray target-local star exists, allowing the gate to use the wrong source. Review comment:
|
…ATH identity unconditionally Separate Fabrica-self CLASSIFICATION (path-based, resolver) from AUTHORIZATION (committed-based, gate) so a stray committed .fabrica/north-star.md can never shadow Fabrica-self. - ns_resolve: on a PATH identity match (toplevel == fabrica_root), return FABRICA_SELF <root>/NORTH_STAR.md UNCONDITIONALLY. Removed the round-2 `git cat-file -e HEAD:NORTH_STAR.md` existence gate that let a control-plane cwd with an uncommitted root fall through to the LOCAL branch and authorize a stray committed .fabrica/north-star.md as Fabrica's star. - manager-review.sh FABRICA_SELF branch: authorization still requires a COMMITTED root (`git show HEAD:NORTH_STAR.md`). Reordered so the committed read runs BEFORE the symlink guard — a missing committed root now FAILs with the accurate "not committed at HEAD" message (does NOT fall back to .fabrica, and no longer mis-reports an absent root as a symlink). FAIL path is set -e-safe (condition context). - doctor.sh / setup-target-repo.sh unchanged: neither gated classification on committed existence; doctor's FABRICA_SELF-uncommitted-root WARN (L383) is now correctly reachable. - Tests: +resolver (c-no-committed-root) [57->59], +gate (2d) missing-root FAILs not LOCAL [66->69]. All existing asserts green. shellcheck 0.9.0 clean; bash -n clean; structure check ok. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Round-3 [P2] — Fabrica-self path identity classifies as FABRICA_SELF unconditionally (head FABRICA_SELF is now classified purely by PATH identity; a missing committed root FAILs at the gate instead of falling through to
Tests (all existing asserts kept green):
Verification: shellcheck 0.9.0 (CI's version) |
Codex reviewer (cross-vendor, read-only)Reviewed-head: db7ba36 Posted verbatim by The target-local north-star gate is mostly implemented, but the migration leaves users pointed at stale setup documentation and doctor can still miss uncommitted north-star changes for Fabrica-self runs. Full review comments:
|
…tted_relpath; docs to per-target model FIX 1 — scripts/doctor.sh: drive the head-vs-worktree "differs from HEAD" note off $committed_relpath (the exact path the gate reads), not a hardcoded .fabrica-relative guard, so a Fabrica-self checkout (committed_relpath = NORTH_STAR.md) also warns on an uncommitted ROOT north-star edit instead of a misleading silent pass. Adds a doctor test (Fabrica-self clone, dirty root star) that fails against the old hardcoded check. FIX 2 — reviewer/manager-review.md: the doc the gate's FAIL message points at now describes the per-target committed model — the debate is judged against the target's committed .fabrica/north-star.md (Fabrica-self uses its root NORTH_STAR.md), read committed at HEAD. Adds a "north star" section; corrects the step-0 gate check, the how-it-runs step 1, the drop-log location, and the prompt. FIX 3 — scripts/install.sh: next-step output now tells adopters to set + commit + approve .fabrica/north-star.md per target (Fabrica-self uses its own root NORTH_STAR.md), matching the shipped gate. Prompt/doc sync note: reviewer/manager-review.md and install.sh's printed text take effect immediately (doc + script output); no /faber regeneration needed for these. Broader narrative docs sweep (README/QUICKSTART/RESTORE/root CLAUDE.md/ templates/repo-setup.md) remains 98b — out of scope here. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Round-3 [P2] consistency fixes applied (head
The broader narrative docs sweep ( Verification: gate suite 71 passed / 0 failed (was 69; +2 from the new drift asserts), resolver suite 59 passed / 0 failed, Prompt/doc sync note: these are a doc ( |
Codex reviewer (cross-vendor, read-only)Reviewed-head: 4bf14fd Posted verbatim by The per-target north-star switch misses linked worktrees of the Fabrica repo itself, causing self-runs from those worktrees to be treated as external targets and potentially seeded with the wrong north-star file. Review comment:
|
… round-3 [P2]) The Fabrica-self identity check was strict top-level PATH equality (toplevel == fabrica_root). Faber operates from a LINKED WORKTREE (.claude/worktrees/*), whose `git rev-parse --show-toplevel` is the worktree path while ns_fabrica_root returns the MAIN checkout path — so the compare FALSELY FAILed and the Fabrica worktree was misclassified as an external target (manager-review/doctor skipped the root NORTH_STAR.md; setup could seed .fabrica/north-star.md into it). Fix: identify Fabrica-self by SHARED GIT COMMON-DIR — the same signal round-1's nested-repo guard (FIX F) uses. New ns_git_common_dir helper canonicalizes `git rev-parse --git-common-dir` to an absolute physical path; ns_resolve classifies FABRICA_SELF iff the target's common-dir equals Fabrica's own (keeping the top-level PATH match as one accepted case). A linked worktree shares its parent's common-dir → self; a genuinely separate repo (different common-dir) → not self. Applied the same common-dir self-check to setup-target-repo.sh's cwd_is_fabrica_self guard (skips seeding in a Fabrica worktree). Comments/messages updated from "PATH identity" to git-structural identity. Tests: +2 resolver cases (linked worktree → FABRICA_SELF; separate repo → not falsely self) and +1 gate case (setup from a Fabrica worktree skips the seed). Resolver 62 pass, gate 73 pass (all prior asserts green). shellcheck 0.9.0 clean; structure check + bash -n green. Prompt-sync note: no prompt/command artifacts changed — this is shipped-tooling (scripts/lib + scripts/*.sh) behavior, live on merge; no install.sh re-run or persona re-read needed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Fabrica-self identity now recognizes linked worktrees via shared git common-dir (consistent with the nested-repo guard).
|
Codex reviewer (cross-vendor, read-only)Reviewed-head: 7ebaa62 Posted verbatim by The production changes appear coherent, but the newly added gate test can hang during local interactive execution because its fake codex blocks on stdin for doctor probes. Review comment:
|
The fake `codex` stub unconditionally ran `cat >/dev/null`, draining stdin for every invocation. But doctor.sh probes codex WITHOUT piping stdin (`codex login --help` / `codex login status`), so a local interactive run of `bash scripts/test/north-star-gate.test.sh` blocked waiting on terminal input (CI masked it by closing stdin). The stub now drains stdin only for the real gate call — `exec` subcommand whose trailing positional is `-` — and exits 0 without touching stdin for non-exec probes, preserving their observable behavior (no stdout, exit 0). Test-only; no production script changed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Fake Verified: both suites green (gate 73/73, resolver 62/62), completing in ~1s even with a never-closing FIFO on stdin (proving no stdin block). Shellcheck 0.9.0 clean ( |
Codex reviewer (cross-vendor, read-only)Reviewed-head: 11d335b Posted verbatim by The per-target north-star wiring mostly follows the intended committed-source model, but setup's new worktree-only missing-file checks leak into doctor as a hard failure and can seed a placeholder over an already committed star that is merely deleted locally. Full review comments:
|
…in, drop seeding tests (#98) Seeding a target's .fabrica/north-star.md is adoption scope → moves to 98b. Removing it from 98a eliminates the churn source and fixes two P2s by removing their cause: - doctor (g) no longer hard-fails on a missing north star: setup-target-repo.sh --check returns to label-only drift (which doctor (g) consumes), so a missing star can't wrongly hard-fail the label check. - no seed-over-committed risk: setup no longer writes .fabrica/north-star.md. Changes: - Revert scripts/setup-target-repo.sh to origin/main (drops the north-star seed, the cwd-slug/common-dir seed-guard, the Fabrica-self seed-exempt, and the --check north-star-missing drift). - Remove the section-(5) seeding asserts from north-star-gate.test.sh (5a/5b/5c/5d/5e) plus their runner invocations; sync the suite header. - Sync the ci.yml gate-step comment to drop the seeding reference. The authorization core is unchanged: the resolver (incl. ns_git_common_dir and the PATH/common-dir Fabrica-self identity), the manager-review.sh committed-read gate + placeholder-FAIL, and doctor (h) all stay. All resolver-identity asserts stay. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Seeding removed from 98a (head Reverted This removes the cause of the two P2s (rather than patching around them):
The atomic flip core is unchanged: the resolver (incl. Test changes: removed the section-(5) seeding asserts from Verification (local):
Do not merge / do not approve — for review. |
Codex reviewer (cross-vendor, read-only)Reviewed-head: 3ab6fae Posted verbatim by The patch has a real gate-bypass bug in marker detection for large north-star files, and its new unset-star remediation points users to a command that does not create the required file. These should be fixed before the change is considered correct. Full review comments:
|
…ale seed remediation text [P2] [P1] ns_active_region's awk exited early once the active region ended (next heading/rule). Callers run 'printf ... | ns_has_shipped_default_marker -' under set -o pipefail; for a large committed .fabrica/north-star.md (placeholder marker in the active entry + tens of KB of body after the next section, enough to fill the pipe buffer) the early exit closed awk's stdin, SIGPIPE'd the upstream printf (141), and pipefail turned that 141 into the whole pipeline's status -> the 'if ns_has_shipped_default_marker' condition read FALSE even though the marker matched -> the gate proceeded against a shipped placeholder and doctor missed the WARN (a placeholder-FAIL bypass). The awk now NEVER exits early: it latches the region closed (in_region=0, done=1) and keeps reading every line to EOF, emitting nothing further. Emitted bytes are byte-identical to the old behaviour (same first active region, nothing after) and a !done guard keeps it to the first region, so the marker verdict is unchanged for all existing cases -- only stdin-draining changes, closing the bypass. New regression test (q): a ~250KB placeholder star still MATCHES under pipefail (reproduced rc=141 pre-fix), and a large correctly-replaced star still returns a clean no-match. [P2] Seeding was stripped from setup-target-repo.sh (label-only now). Updated every user-facing message that told the operator setup seeds .fabrica/north-star.md to instead say: copy templates/.fabrica/north-star.md into the target, replace the placeholder, remove the fabrica-shipped-default marker, then commit + approve it (setup only creates the loop labels). Fixed in scripts/manager-review.sh (no-committed-star FAIL message), templates/.fabrica/north-star.md, scripts/install.sh next-step, and scripts/setup-target-repo.sh step-6 follow-up; plus a stale 'setup would seed' rationale comment in scripts/lib/north-star.sh. Preserves every authorization rail (this FIXES a bypass). shellcheck 0.9.0 clean; resolver suite 64 passed / gate suite 62 passed; structure check ok. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Round-3 Codex findings addressed (head
|
Codex reviewer (cross-vendor, read-only)Reviewed-head: aacd040 Posted verbatim by The manager-review gate can still proceed on a malformed committed north-star file that has no active entry, which undermines the new per-target authorization check. This should be fixed before the patch is considered correct. Review comment:
|
…ntry A committed .fabrica/north-star.md (or the control plane's NORTH_STAR.md) with content but NO valid `status: active` heading — e.g. the marker was mistyped or removed when editing the template — previously slipped past the gate: the shipped-default marker check is false (no active region → no marker) AND the file exists (so it is not UNSET), so the gate PROCEEDED to debate Codex against a goalless file. Proactive work is authorized ONLY by an approved ACTIVE north star. Fix: in manager-review.sh, after reading the committed north star on an authorized path (FABRICA_SELF root or LOCAL .fabrica/north-star.md), require a non-empty active region via the shared ns_active_region helper (same committed content already read; same helper doctor's (h) check uses). This sits alongside the existing UNSET-FAIL and placeholder-FAIL, closing the goalless-debate gap between them. doctor.sh already WARNs on this condition (line 372) — proactive gate FAILs, doctor warns, user-directed work stays valid. Test: new gate case (10) — a committed star with no `status: active` heading FAILs before any Codex verdict; normal active entry / placeholder / UNSET unchanged. Four existing PROCEED tests that used plain-prose stars now carry a `status: active` heading (their intent is "a real committed star authorizes"). Gate suite 62 → 65; resolver suite 64 unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
[P2] fixed — the manager-debate gate now FAILs when the committed north star has no active entry. Previously a committed Fix (
Tests: new gate regression No safety rail weakened — this closes an authorization gap (goalless debate). |
Codex reviewer (cross-vendor, read-only)Reviewed-head: 13d8981 Posted verbatim by The implementation adds a new committed per-target north-star requirement, but several user-facing setup documents still direct users to the old control-plane file, leaving documented onboarding paths broken. Review comment:
|
…nd-3 [P2]) README, QUICKSTART, and templates/repo-setup.md still pointed operators at the control-plane NORTH_STAR.md as *the* north star. Flip them to the per-target model: each target repo's own committed .fabrica/north-star.md (copied from the shipped template, placeholder replaced, fabrica-shipped-default marker removed, committed) is the star Faber gates on; the root NORTH_STAR.md is now only Fabrica-self's own target file (resolver returns it for a Fabrica-self run). Docs-only; matches the already-flipped /faber, manager/CLAUDE.md, manager-review.md, install.sh, and the resolver gate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Swept the remaining onboarding/setup docs to the per-target `.fabrica/north-star.md` model so every documented path matches the already-flipped gate (Codex final [P2]). Head now `71eae3c`. Docs-only — no code/logic change. Files swept:
No changes needed in RESTORE.md or the root CLAUDE.md — their only north-star mentions are the location-agnostic decision-altitude / approval-path sense ("north-star / goal drift", "approved the active north star"), which stay correct under the flip. No literal `NORTH_STAR.md` file-location onboarding refs remain there. Verification:
Greenfield tie-in (bootstrap creates the target's `.fabrica/north-star.md`) and the MapleFolio history log remain 98b / #100. |
Codex reviewer (cross-vendor, read-only)Reviewed-head: 71eae3c Posted verbatim by No actionable correctness issues were identified in the changed scripts, tests, or documentation. The north-star resolution and gate changes appear internally consistent and covered by the added test suite. |
Per-target north star (98a) — the atomic gate + doctor + persona flip, reading COMMITTED state
Closes #98. Manager-debate reached PROCEED (Faber⇄Codex consensus). This activates the dormant #99 resolver atomically, so the consensus gate's source and Faber's approval source flip together and read committed target state — the recurring inconsistency #99 was reset to avoid.
The 5 build items (all in this one PR)
manager-review.sh→ resolver, COMMITTED read, pinned commit. Resolves the north star for the target vians_resolve, then reads its committed content withgit show "$head_commit:.fabrica/north-star.md"— pinned to the same commit the detached review worktree is materialized at (head_commit, captured once), never a free-floating later HEAD. A star that exists only as an uncommitted worktree edit does NOT authorize (→ UNSET → FAIL before any Codex verdict). A LOCAL star still carrying thefabrica-shipped-defaultmarker → FAIL (un-replaced placeholder). FABRICA_SELF is exempt from the placeholder-FAIL (its rootNORTH_STAR.mdis Fabrica's real approved goal).doctor.shcheck (h) → resolver (target). Reads the target's star via the resolver, consistent with the gate. UNSET → WARN (not FAIL) — doctor only diagnoses. Marker/staleness semantics +|| trueguards preserved; diagnostic reads the working-tree copy and notes when it differs from HEAD.templates/faber-command.md+manager/CLAUDE.mdnow reference the resolved target (committed).fabrica/north-star.mdas the operator-approval + logging source, not{{FABRICA_ROOT}}/NORTH_STAR.md(the Fabrica-self exception is kept). Gate source ≡ approval source — stated explicitly so they never diverge. The template was edited (not the generated output).setup-target-repo.shseeding re-added (reverted in Per-target north star (1/3): dormant resolver foundation (lib + adopter template + tests); consumers switch atomically in #98/98a #99's reset; recovered from history and re-applied): seeds<target>/.fabrica/north-star.mdfrom the template if absent — idempotent (never overwrites), guarded by cwd-slug == target-slug vians_slug_eq(env -u GH_REPOfor the slug), and--checkreports a missing star as drift.templates/.fabrica/north-star.md→ present tense — drops the "dormant / Per-target north star (98a): atomic gate+doctor+persona flip, reading committed target state #98 pending" hedge, states that setup/doctor/manager-review use it; keeps thefabrica-shipped-defaultmarker + the "replace, then remove the marker, then commit" nudge.How the committed read is pinned to a single commit
head_commit="$(git rev-parse HEAD)"is captured once. The review worktree is added at that exact commit (git worktree add --detach "$worktree" "$head_commit"), and the north-star content is read from the same commit (git show "${head_commit}:…"). One pin, no re-lookup — so the gate's goal is exactly the committed tree Codex reviews, immune to the dirty working tree.Note on the resolver:
ns_resolveclassifies the source via its identity logic (Fabrica-self vs. target), but its LOCAL-vs-UNSET result is working-tree-based, so the gate does not use it to authorize. For a normal target the authoritative authorize test is whether.fabrica/north-star.mdexists athead_commit— which is what makes a committed-but-worktree-deleted star still authorize.Tests (
scripts/test/north-star-gate.test.sh, 30 asserts, CI-wired)Runs the real scripts end-to-end against throwaway real git repos with
gh/codexfaked on PATH (hermetic, offline). Highlights:--checkflags missing star as drift, seed idempotency.The #99 resolver-lib suite stays green (33 asserts). Added the new test to
ci/required-files.txtand.github/workflows/ci.yml.CI green locally
-x -S style— clean across all*.shbash -non every changed script — okThe scripts take effect on merge. The live
/fabercommand changes only after re-runningscripts/install.shfrom the merged clone (this PR edits the template, not the generated~/.claude/commands/faber.md). The persona (manager/CLAUDE.md) takes effect the next time Faber reads it. This is the safety-critical atomic flip — gate source ≡ approval source, committed-only — the rail being preserved, not weakened. Every other rail is intact (reviewer read-only, CI merge gate, rounds cap,needs-human, merge SHA-pin).Out of scope → 98b: docs sweep (README/QUICKSTART/RESTORE/root CLAUDE.md/reviewer-doc/repo-setup), greenfield tie-in, MapleFolio history, migration guidance.
🤖 Generated with Claude Code