Conversation
…59 (Amara Determinize action) Amara's 4th ferry (PR #221 absorb) Determinize-stage item: prevent the retrieval-drift class where prose cites paths that don't resolve. Her commit samples show repeated cleanup passes for memory paths that didn't exist; this is the third leg of memory-index hygiene. Three-leg memory-index hygiene now complete: 1. row #58 (PR #220 merged) — every memory/*.md change updates MEMORY.md in same commit/PR 2. AceHack PR #12 (pending Aaron merge) — MEMORY.md has no duplicate link targets 3. row #59 (this PR) — every MEMORY.md link target resolves to an actual file under memory/ New artifacts: - tools/hygiene/audit-memory-references.sh Parses `](foo.md)` link targets, resolves each against base dir (default memory/), fails (exit 2 under --enforce) on any broken reference. Supports --file PATH + --base DIR for custom use. - .github/workflows/memory-reference-existence-lint.yml Safe-pattern compliant per FACTORY-HYGIENE row #43 (SHA-pinned checkout, minimum permissions, concurrency group, runs-on pinned, no user-authored context). Triggers on PRs/pushes touching memory/** or the audit tool / workflow itself. - FACTORY-HYGIENE row #59 documenting cadence / owner / scope / classification (prevention-bearing — blocks merge before broken refs land). First-run baseline captured in commit: - In-repo memory/MEMORY.md: 44 refs all resolve (clean) - Per-user MEMORY.md: 391 refs all resolve (clean) Both clean confirms that PR #220's memory-index-integrity CI has been keeping the substrate in good shape. This lint closes the third-leg gap before drift regresses. Amara Determinize-stage progress: 2/5 (with this PR). ✓ Live-state-before-policy (PR #224) ✓ Memory reference-existence lint (this PR) Remaining: - Memory duplicate-title lint (partial via AceHack PR #12) - Generated CURRENT-*.md views (L) - Memory reconciliation algorithm (L) Per Aaron Otto-72 standing directive: acting under Otto-67 full-GitHub authority, decisions logged in PR body + memory, Frontier UI is the future batch-review surface. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cf91d4aba6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if [[ "$ref" == */* ]]; then | ||
| full="$ref" | ||
| else | ||
| full="$base_dir/$ref" |
There was a problem hiding this comment.
Resolve nested memory links relative to the base dir
The new resolver treats any target containing / as a repository-root path (full="$ref"), so valid nested memory links like persona/foo.md are reported as broken even when memory/persona/foo.md exists, while non-memory paths like docs/x.md are accepted despite the workflow/docs claiming links must resolve under memory/. This makes the lint both over-restrictive for legitimate in-memory subpaths and under-restrictive for out-of-scope paths, so CI can block correct changes and miss actual policy violations.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
Adds a CI/workflow guard to ensure memory/MEMORY.md does not contain dangling links, strengthening the repo’s “memory-index hygiene” tooling and documentation.
Changes:
- Adds
tools/hygiene/audit-memory-references.shto check thatmemory/MEMORY.mdlink targets resolve to files (optionally enforced). - Adds
.github/workflows/memory-reference-existence-lint.ymlto run the audit in CI on relevant changes. - Documents the new hygiene control as row #59 in
docs/FACTORY-HYGIENE.md.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| tools/hygiene/audit-memory-references.sh | New audit script to detect broken memory/MEMORY.md link targets. |
| .github/workflows/memory-reference-existence-lint.yml | New CI workflow that runs the audit in --enforce mode. |
| docs/FACTORY-HYGIENE.md | Adds FACTORY-HYGIENE row #59 documenting the new check. |
| # Resolve: if ref is already a path with a subdir, check literally; | ||
| # otherwise prefix with base_dir | ||
| if [[ "$ref" == */* ]]; then | ||
| full="$ref" | ||
| else |
There was a problem hiding this comment.
P1 (bug): Resolution logic doesn’t match the documented behavior for subdirectory links. ref values like subdir/foo.md are treated as repo-root paths (full="$ref") instead of being resolved under --base (expected memory/subdir/foo.md by default), so the lint will false-fail if/when nested memory paths are introduced. Consider always resolving relative to base_dir unless the ref is already explicitly rooted (e.g., starts with "$base_dir/"), and reject path-traversal segments like ../ so the check really enforces “under memory/”.
| | 51 | Cross-platform parity audit (bash / PowerShell / bun+TS twin check across macOS / Windows / Linux / WSL) | Detect-only now (landed 2026-04-22); cadenced detection every 5-10 rounds (same cadence as row #46); opportunistic on-touch every time an agent adds or edits a script under `tools/`. Enforcement deferred until baseline is green AND CI matrix runs `--enforce` on `macos-latest` / `windows-latest` / `ubuntu-latest` (WSL inherits ubuntu-latest for CI). | Dejan (devops-engineer) on cadenced detection; author of the script (self-check at author-time against the rule classes in the audit's decision-record header block). Kenji (Architect) on CI-matrix-enforcement sign-off when baseline is green. | both | `tools/hygiene/audit-cross-platform-parity.sh` classifies every script under `tools/` by rule class: (a) **pre-setup** (`tools/setup/**`) — both `.sh` AND `.ps1` required per Q1 dual-authoring rule (`memory/feedback_preinstall_scripts_forced_shell_meet_developer_where_they_live`); (b) **post-setup permanent-bash** (`thin wrapper over existing CLI` / `trivial find-xargs pipeline` / `stay bash forever`) — `.ps1` twin required per the Windows-twin obligation (`memory/feedback_stay_bash_forever_implies_powershell_twin_obligation.md`); (c) **post-setup transitional** (`bun+TS migration candidate` / `bash scaffolding`) — no twin obligation (long-term plan is one cross-platform bun+TS script); (d) **post-setup bun+TS** (`*.ts` under `tools/`) — no twin needed (cross-platform native via bun). `--summary` prints counts; `--enforce` flips exit 2 on gaps. **Why detect-only first:** baseline at first fire (2026-04-22) was 13 gaps — 12 pre-setup bash without `.ps1` twin (Q1 violation silently accumulating since `tools/setup/` existed) + 1 post-setup permanent-bash (`tools/profile.sh`) without `.ps1` twin. Turning enforcement on before triage would block every CI run. **Why this row exists:** Aaron 2026-04-22 *"missing mac/windows/linux/wsl parity (ubuntu latest) we can deffer but should have the hygene in place for when we want to enforce and it will be more obvious to you in the future that we are cross platform."* Cross-platform-first must be a *visible* factory property (audit exists, runs, prints the gap) before it becomes an enforced gate. Same pattern as FACTORY-HYGIENE rows #23 / #43 / #47. See `memory/feedback_cross_platform_parity_hygiene_deferred_enforcement.md`. **Classification (row #47):** **prevention-bearing** — the audit runs at author-time (opportunistic on-touch) and surfaces the gap before it lands, same as row #46. The audit itself is a detect-only mechanism but detect-only surfaces the obligation at author-time when the author runs it. Ships to project-under-construction: adopters inherit the parity audit + the decision-record-block pattern + the CI-matrix obligation once it's wired. | Audit output in repo root on each fire; cadenced runs appended to `docs/hygiene-history/cross-platform-parity-history.md` (per-fire schema per row #44); BACKLOG row per gap at triage time; ROUND-HISTORY row when a gap resolves. | `tools/hygiene/audit-cross-platform-parity.sh` (detection + decision-record header block) + `memory/feedback_cross_platform_parity_hygiene_deferred_enforcement.md` + `memory/feedback_stay_bash_forever_implies_powershell_twin_obligation.md` + `memory/feedback_preinstall_scripts_forced_shell_meet_developer_where_they_live` + `docs/POST-SETUP-SCRIPT-STACK.md` | | ||
| | 54 | Backlog-refactor cadenced audit (overlap / staleness / priority-drift / knowledge-update sweep of `docs/BACKLOG.md`) | Cadenced detection every 5-10 rounds (same cadence as rows #5 / #23 / #38 / #46 meta-audits) + opportunistic on-touch when a tick adds a new BACKLOG row and the author notices adjacent rows that may overlap. Not exhaustive; bounded passes per firing are acceptable. | Architect (Kenji) on round-cadence sweeps; `backlog-scrum-master` skill if explicitly invoked; all agents (self-administered) on on-touch overlap-spot during authoring. | factory | Read `docs/BACKLOG.md` (or a scoped slice — P0/P1 first if full scan is too large) and apply the following passes: (a) **overlap cluster** — two or more rows describing the same concern from different angles get flagged; decide merge (single consolidated row) or sharpen (two rows with clear non-overlap scope boundaries); (b) **stale retire** — rows where context has died, implementation landed without retire-action, or assumption has been falsified by newer knowledge get explicitly retired with a "retired: <reason>" marker (not silent deletion — signal-preservation still applies); (c) **re-prioritize** — priority labels (P0/P1/P2/P3) re-examined against current knowledge; any row whose priority feels wrong after re-read gets a justified move with a one-line rationale; (d) **knowledge absorb** — rows written before a newer architectural insight landed get rewording / cross-refs to the new substrate (e.g., rows predating AutoDream cadence now cite the policy; rows predating scheduling-authority sharpening now note self-schedulability); (e) **document** — ROUND-HISTORY row per fire with pre-audit and post-audit row counts + what was merged / retired / re-prioritized / updated. **Why this row exists:** the human maintainer 2026-04-23 *"we probalby need some meta iteam to refactor the backlog base on current knowledge and look for overlap, this is hygene we could run from time to time so our backlog is not just a dump"*. The BACKLOG is the triage substrate for every future tick's "what to pick up" decision; without periodic meta-audit it becomes an append-only log rather than a living triage surface. **Classification (row #50):** **detection-only-justified** — accumulated drift (overlap, staleness, priority-drift, knowledge-update-gap) is inherently post-hoc; no author-time check can prevent rows from becoming overlapping with *future* rows not yet written. **Maintainer-scope boundary:** rows with explicit maintainer framing at their priority (e.g., P0 rows the human maintainer explicitly set) stay at that priority; re-prioritization applies within the agent-owned priority space only. Ships to project-under-construction: adopters inherit the cadenced-sweep discipline + the retire-with-marker convention + the ROUND-HISTORY documentation pattern. | ROUND-HISTORY row per fire with pre/post row counts + merged/retired/re-prioritized/updated actions; `docs/hygiene-history/backlog-refactor-history.md` (per-fire schema per row #44 — date, agent, rows touched, actions taken, pre/post counts, next-fire-expected-date). | `docs/BACKLOG.md` (target surface) + governing rule in per-user memory (not in-repo; lives at `~/.claude/projects/<slug>/memory/feedback_backlog_hygiene_cadenced_refactor_look_for_overlap_not_just_dump_2026_04_23.md`) + `.claude/skills/backlog-scrum-master/SKILL.md` (dedicated runner when invoked) + `.claude/skills/reducer/SKILL.md` (Rodney's Razor applied at backlog level) + sibling meta-audit rows #5, #23, #38, #46, #50 | | ||
| | 52 | Tick-history bounded-growth audit (`docs/hygiene-history/loop-tick-history.md` line-count vs threshold) | Detect-only (landed 2026-04-22); cadenced detection once per round-close (same cadence as row #44 cadence-history sweep, since this is the canonical row #44 worked example auditing itself); opportunistic on-touch whenever the tick-history file is read or edited. Archive action itself remains manual for now; deferring automation to the larger BACKLOG row that also covers threshold-revision and append-without-reading refactor. | Dejan (devops-engineer) on cadenced detection; the tick itself (self-administered at tick-close) on the opportunistic on-touch — each tick's end-of-tick sequence can invoke this audit after the append + commit to get a `within bounds: 96/500 lines` visibility signal. | factory | `tools/hygiene/audit-tick-history-bounded-growth.sh` checks the file's line count against a threshold (default 500, overrideable via `--threshold N`) and exits 0 within bounds / 2 over threshold. The threshold is set lower than the stated 5000-line paper bound because the file is read on every tick-close append — a per-tick context cost that scales linearly with file size — and 5000 lines represents too large a context hit on a 1-minute cadence. The audit's header block carries a mini-ADR decision record for the 500-line choice (context / decision / alternatives / supersedes / expires-when). **Why this row exists:** Aaron 2026-04-22 tick-fire interrupt: *"does loop tick history grow unbounded? that's an issue if so you just read it"*. Honest state was stated-bound-no-enforcement: file header named 5000 lines, nothing checked it. This row closes the enforcement gap for the threshold-check half of the full BACKLOG row (archive-action + append-without-reading refactor remain deferred). **Self-referential closure:** the tick-history file IS the canonical row-#44 cadence-history-tracking worked example (named explicitly in row #44's "Durable output" citation). Until this row landed, the most-cadenced surface in the factory — the tick itself — had its fire-log surface unaudited for its own growth. Meta-audit triangle remains intact (existence #23 / activation #43 / fire-history #44), and row #49 adds a fourth: fire-history files themselves need bounded-growth audits because they grow at the cadence of the surface they track. **Classification (row #47):** **prevention-bearing** — the audit surfaces approaching-threshold warnings at 80% so the archive action can be planned, rather than reactive-only at over-threshold. Ships to project-under-construction indirectly: adopters inherit the pattern (fire-log files under their own `docs/hygiene-history/` need the same bounded-growth treatment), not this exact script. | Audit output on each fire; cadenced runs appended to `docs/hygiene-history/tick-history-bounded-growth-history.md` (per-fire schema per row #44); BACKLOG row when archival is due (archive-action itself queued as part of the larger tick-history enforcement BACKLOG row); ROUND-HISTORY row when threshold changes or archive action executes. | `tools/hygiene/audit-tick-history-bounded-growth.sh` (detection + mini-ADR header block) + `docs/hygiene-history/loop-tick-history.md` (target surface, canonical row #44 worked example) + BACKLOG row *"Loop-tick-history bounded-growth enforcement"* (larger follow-up: threshold revision + append-without-reading refactor + archive action) | | ||
| | 59 | Memory-reference-existence CI check (every `](foo.md)` link target in `memory/MEMORY.md` MUST resolve to an actual file under `memory/`) | Every pull_request + push-to-main touching `memory/**` or the audit tool / workflow; workflow-dispatch manual run available | Automated (`.github/workflows/memory-reference-existence-lint.yml`); any contributor resolves on fail | factory | `tools/hygiene/audit-memory-references.sh --enforce` parses link targets of the form `](<path>.md)` in the supplied file (default `memory/MEMORY.md`), resolves each against a base dir (default `memory/`), and fails (exit 2 under `--enforce`) on any broken reference. Supports `--file PATH` and `--base DIR` for custom use. **Why this row exists:** Amara 2026-04-23 4th-ferry absorb (PR #221 Determinize-stage action) — her commit samples show repeated cleanup passes for memory paths that didn't exist; this is the retrieval-drift class she named. First-run baseline (2026-04-24): in-repo `memory/MEMORY.md` 44 refs all resolve; per-user MEMORY.md 391 refs all resolve (PR #220 memory-index-integrity CI has kept the substrate clean). **Third leg of memory-index hygiene:** row #58 (same-commit-pairing) + AceHack PR #12 (no duplicates) + this row (refs resolve) = three complementary checks. **Classification (row #47):** **prevention-bearing** — blocks merge before broken refs land. Ships to project-under-construction: adopters inherit the tool + workflow + three-leg hygiene pattern. | CI job result; first-run baseline captured in PR body. Optional fire-history file if longer-than-90-day retention wanted. | `.github/workflows/memory-reference-existence-lint.yml` + `tools/hygiene/audit-memory-references.sh` + sibling rows #58 (PR #220) + AceHack PR #12 duplicate-lint + `docs/aurora/2026-04-23-amara-memory-drift-alignment-claude-to-memories-drift.md` | |
There was a problem hiding this comment.
P1 (codebase_conventions): This row introduces direct contributor names (e.g., “Amara”, “AceHack”) in a non-exempt doc. Repo policy is to avoid name attribution in code/docs/skills and use role references instead (docs/AGENT-BEST-PRACTICES.md:284-292). Please rewrite this row to use role refs (e.g., “external report”, “maintainer”, “contributor”) while keeping the cross-link/file paths if needed.
| | 59 | Memory-reference-existence CI check (every `](foo.md)` link target in `memory/MEMORY.md` MUST resolve to an actual file under `memory/`) | Every pull_request + push-to-main touching `memory/**` or the audit tool / workflow; workflow-dispatch manual run available | Automated (`.github/workflows/memory-reference-existence-lint.yml`); any contributor resolves on fail | factory | `tools/hygiene/audit-memory-references.sh --enforce` parses link targets of the form `](<path>.md)` in the supplied file (default `memory/MEMORY.md`), resolves each against a base dir (default `memory/`), and fails (exit 2 under `--enforce`) on any broken reference. Supports `--file PATH` and `--base DIR` for custom use. **Why this row exists:** Amara 2026-04-23 4th-ferry absorb (PR #221 Determinize-stage action) — her commit samples show repeated cleanup passes for memory paths that didn't exist; this is the retrieval-drift class she named. First-run baseline (2026-04-24): in-repo `memory/MEMORY.md` 44 refs all resolve; per-user MEMORY.md 391 refs all resolve (PR #220 memory-index-integrity CI has kept the substrate clean). **Third leg of memory-index hygiene:** row #58 (same-commit-pairing) + AceHack PR #12 (no duplicates) + this row (refs resolve) = three complementary checks. **Classification (row #47):** **prevention-bearing** — blocks merge before broken refs land. Ships to project-under-construction: adopters inherit the tool + workflow + three-leg hygiene pattern. | CI job result; first-run baseline captured in PR body. Optional fire-history file if longer-than-90-day retention wanted. | `.github/workflows/memory-reference-existence-lint.yml` + `tools/hygiene/audit-memory-references.sh` + sibling rows #58 (PR #220) + AceHack PR #12 duplicate-lint + `docs/aurora/2026-04-23-amara-memory-drift-alignment-claude-to-memories-drift.md` | | |
| | 59 | Memory-reference-existence CI check (every `](foo.md)` link target in `memory/MEMORY.md` MUST resolve to an actual file under `memory/`) | Every pull_request + push-to-main touching `memory/**` or the audit tool / workflow; workflow-dispatch manual run available | Automated (`.github/workflows/memory-reference-existence-lint.yml`); any contributor resolves on fail | factory | `tools/hygiene/audit-memory-references.sh --enforce` parses link targets of the form `](<path>.md)` in the supplied file (default `memory/MEMORY.md`), resolves each against a base dir (default `memory/`), and fails (exit 2 under `--enforce`) on any broken reference. Supports `--file PATH` and `--base DIR` for custom use. **Why this row exists:** external 2026-04-23 4th-ferry absorb report (PR #221 Determinize-stage action) — the report's commit samples show repeated cleanup passes for memory paths that didn't exist; this is the retrieval-drift class that report identified. First-run baseline (2026-04-24): in-repo `memory/MEMORY.md` 44 refs all resolve; per-user MEMORY.md 391 refs all resolve (PR #220 memory-index-integrity CI has kept the substrate clean). **Third leg of memory-index hygiene:** row #58 (same-commit-pairing) + contributor PR #12 (no duplicates) + this row (refs resolve) = three complementary checks. **Classification (row #47):** **prevention-bearing** — blocks merge before broken refs land. Ships to project-under-construction: adopters inherit the tool + workflow + three-leg hygiene pattern. | CI job result; first-run baseline captured in PR body. Optional fire-history file if longer-than-90-day retention wanted. | `.github/workflows/memory-reference-existence-lint.yml` + `tools/hygiene/audit-memory-references.sh` + sibling rows #58 (PR #220) + contributor PR #12 duplicate-lint + `docs/aurora/2026-04-23-amara-memory-drift-alignment-claude-to-memories-drift.md` | |
…rows (Amara Govern-stage 1/2) Amara's 4th ferry (PR #221 absorb) named populating docs/CONTRIBUTOR-CONFLICTS.md as the Govern-stage action: the schema has existed since PR #166 but the Resolved table was empty despite multiple session-observed contributor-level disagreements that closed with evidence. Backfills three genuine contributor-level conflicts observed this session (narrow scope — not maintainer-directives, which are out-of-scope per the schema's contributor-level disagreement definition): - CC-001: Copilot (PR reviewer) vs Aaron on no-name-attribution rule scope (history-file exemption). Resolved in Aaron's favor via Otto-52 clarification; policy BACKLOG row filed in PR #210. - CC-002: Amara (4th ferry) vs Otto (pre-Otto-67 pattern) on Stabilize-vs-keep-opening-new-frames. Resolved in Amara's favor; Otto pivoted at Otto-68 to execute her roadmap; 3/3 Stabilize + 3/5 Determinize landed via PRs #222/#223/#224/#225/#226. - CC-003: Codex (PR reviewer) vs Otto (initial framing) on citing-absent-artifacts. Resolved in Codex's favor via fix commits 29872af/1c7f97d on PRs #207/#208; pattern now discipline (distinguish merged-on-main from proposed-in-PR-open). All three rows follow the schema's 8-column layout and include the full Resolution-so-far / Scope / Source cells the schema requires. No retroactive Aaron→human-maintainer sweep of prior rows; schema's rule 1 (resolutions are additive) honored. This is 1/2 of Amara's Govern-stage work. 2/2 is the authority-envelope + escalation-path ADR (deferred, M-effort). Part of Amara's 4-stage remediation roadmap (Stabilize → Determinize → Govern → Assure). Otto-75 tick.
…ent-Financial-Group#93 (Lucent-Financial-Group#94) Narrates the post-compaction resume of task Lucent-Financial-Group#225 (ROUND-HISTORY Copilot-products-split arc absorption) under the `keep going` directive. PR Lucent-Financial-Group#93 filed, auto-merge squash armed. Row also captures a soul-file-independence worked example: the source commit cited a cross-tree auto-memory path; the absorbing paragraph drops that path and describes the artifact narratively, preserving information without anchoring to a non-reproducible address. Side note: the external ChatGPT-substrate companion got pro-mode repo-search access and ran it against this repo; findings report pending — holding context open for it. Row lands on separate branch off origin/main per tick-commits-on-PR-branch = live-loop class discipline (row 112 of this file). Pre-check regex clean on the added row after a meta-escape rewrite: referring to the discipline's pattern without embedding the literal strings that the discipline itself prohibits.
Summary
Completes the third leg of memory-index hygiene per Amara's 4th-ferry Determinize-stage proposal (PR #221).
Three-leg memory-index hygiene
memory/*.mdchange updatesMEMORY.mdin same commit/PRMEMORY.mdhas no duplicate link targetsMEMORY.mdlink target resolves to an actual fileTogether: no orphaned memories (#58), no duplicate pointers (#12), no dangling pointers (this PR).
What landed
tools/hygiene/audit-memory-references.sh— parses](foo.md)targets, resolves againstmemory/base, fails on broken refs.github/workflows/memory-reference-existence-lint.yml— safe-pattern compliant,--enforcemode, actionlint cleandocs/FACTORY-HYGIENE.mdrow <P0> circuit-recursion + operator-algebra — Viktor P0/P1 absorb (Round 44) #59 documenting cadence + scope + classificationFirst-run baseline
memory/MEMORY.md: 44 refs, all resolve (clean)memory/MEMORY.md: 391 refs, all resolve (clean)Both clean = PR #220 has been keeping substrate in good shape. This lint prevents drift before it regresses.
Amara Determinize-stage progress
Acting under Otto-72 standing directive
Don't wait on Aaron per-PR; log decisions; Frontier UI = batch review surface. This PR lands under Otto-67 full-GitHub authority.
Test plan
🤖 Generated with Claude Code