athola/night-market-failure-archaeology
Chronicles settled battles, reverts, and dead ends. Use when a fix echoes a past failure. Do not use for live triage; use night-market-debugging-playbook.
npx skills add https://github.com/athola/claude-night-market --skill night-market-failure-archaeology
This is a reference document, not a runbook. It records every major
investigation, dead end, rejected fix, and revert in this repo as
symptom, root cause, evidence, status, and lesson, so nobody re-fights
a settled battle. For triage of a failure happening right now, use
night-market-debugging-playbook. Come here when a proposed change
smells like something the repo already tried and rejected.
Jargon used below:
floor), while the rest of the repo requires Python 3.12. Enforced by
.github/workflows/python39-compat.yml.
and a note in the collective memory, not a hunch.
table for anything resembling your plan.
this time is different before overriding it.
git log --format='%h %s' -1 <hash>.tasks_manager.py copies in attune,sanctum, and spec-kit looked like textbook duplication.
scripts/tasks_manager.py (1,169 lines deleted across 6 files)
broke plugin self-containment. Plugins are independent deployables
that run from a Claude Code cache directory, so they cannot import
from the repo root.
054e2679 (consolidate, 2026-01-23), 29961cd2 (revert,same day), d89a55c7 (differentiated per-plugin copies). All three
copies exist today under plugins/<p>/scripts/tasks_manager.py.
docs/dependency-audit.md tracks cross-plugin deps and fallbacks.
"helpfully" re-consolidate duplicated plugin scripts.
scripts/lsp-proxy.py added for "graceful server fallback"with no consumer demanding it.
2fcb256d (add), killed in PR #193 review, bc318947(revert, 2026-02-11, restores .cclsp.json).
See also .claude/rules/shared-utility-consumer-rule.md.
import graph to decide what was dead.
Python imports. 28 actively referenced scripts plus 18 companion
test files were classified dead and deleted.
a3f11323 (the deletion), 3f280334 (restore the 28scripts and 18 tests), b5f08bf7 (CI repair: dead docs workflow,
missing capabilities entries), d6c128f5 and 01a13e70 (further
repair and governance follow-ups). Recovery point was branch
backup/unbloat-20260328.
(skills, commands, agents), never imports alone. Always take a
backup/unbloat-<date> branch first.
hiding 73 real violations.
06b9b1db (2026-03-10) reverts the bulk ignores and fixesall 73 at source. The commit body cites issue #296 as the
anti-bulk-ignore policy anchor.
suppress per line with a stated reason.
datetime.UTC is a 3.11+ alias. On PR #511 this was the sole
failing check, with three cascade failures rooted in one
ImportError.
timezone.utc back to datetime.UTC, silently re-breaking the fix.
The linter was fighting the fix.
18c9340d (leyline quota_tracker, 2026-05-07),b0049fde (abstract), 709dafc9 (attune).
an AST-scanning test (plugins/leyline/tests/test_python39_compat.py)
fails CI on any reintroduction, root ruff config extend-ignores
UP017, and the surviving per-line pyupgrade suppression markers each
carry a stated reason.
holds the line. A fix commit alone will be reverted by tooling.
git commit emitted a PreToolUse hookModuleNotFoundError.
__init__ eagerly imported dependencies(yaml, anthropic) that the bare host interpreter running hooks does
not have.
45dd77ef (guard yaml import, #518, 2026-05-08),9bfc0a7a (defer anthropic import to function scope). Regression
tests block re-imports with a sys.meta_path blocker
(plugins/gauntlet/tests/unit/test_challenges.py).
must be import-safe under a bare interpreter with no third-party
packages.
verdict at all in the failure case.
LLM_TIMEOUT_SECONDS = 30 inside a hook registered witha 10-second budget. The harness killed the whole hook before the LLM
subprocess returned, so even the deterministic path's verdict was
lost.
3d22f02a (the judge), 268cff89 (2026-05-30: cap LLMtimeout to 8s, gate the LLM second shot to the single ambiguous
outcome). A guard test asserts LLM_TIMEOUT_SECONDS is below the
registered hook timeout
(plugins/herald/tests/unit/test_double_shot_latte.py).
budget in a test. Deterministic tests do not exercise optional
branches, so the optional branch needs its own guard.
so broken inputs produced clean-looking reports. One metric reported
Elite on malformed tags.
parse errors.
666171c3 (2026-06-18, fixes #575, findings B1-B4 fromPR #521), b6de71cf (plugin-check: bound hangs, unmask failures).
skipping silently.
cannot parse an input must say so in its output.
[Learning] discussion digest went quiet after2026-04-25. That starvation was the only visible symptom.
skill_execution_logger,pre_skill_execution, homeostatic_monitor in abstract, leyline
noqa_guard, sanctum deferred_item_watcher) read CLAUDE_TOOL_*
environment variables that Claude Code never populates. The payload
arrives as JSON on stdin. The hooks exited 0 without doing anything,
for months.
reader read_hook_payload in
plugins/abstract/hooks/shared/hook_io.py, with env-var fallback
for the test harness. Consumers: the five hooks above.
actually fire and consume the real payload contract (stdin JSON).
disabled 13 error codes, and the typecheck hook ran --changed
instead of --all.
per-plugin strict mypy with --all, new typecheck.yml workflow
gating every PR.
Audit what a gate actually runs, not whether it passes.
out.
setup-uv@v8 bare tag does not exist upstream, andbandit newer than 1.8.6 dropped Python 3.9 support needed by hooks.
f81d89a5 (pin setup-uv to v8.2.0), 25bf5a9d (pinbandit 1.8.6).
scripts/check_pinned_versions.pyand scripts/check_ruff_version.py (pre-commit, run only when the
relevant files are staged).
trust a major-version alias tag to exist.
gh discussion create/comment/list andfailed. There is no such gh subcommand.
reachable only through the GraphQL API.
with GraphQL mutations). Working templates live in
plugins/leyline/skills/git-platform/modules/command-mapping.md
using gh api graphql.
Discussions goes through gh api graphql, never a gh discussion
subcommand.
per file (PEN-013).
break after the first finding.4993273b (2026-06-22).scanner is a correctness bug, not an optimization.
from the Claude Code cache directory instead of the repo checkout.
plugins execute from a cache dir where sibling repo paths do not
exist.
session-start hook"), later generalized in a8c9e4e9 (vendor
json_utils.sh per plugin).
plugin root, ever. Vendor small utilities per plugin (see SB1: this
duplication is intentional).
because a fallback matched loose body text when frontmatter did not
answer.
authoritative. The fallback masked the real signal instead of
failing loudly.
69fbd32c (2026-06-24, remove the fallback). Patterncodified in .claude/rules/prefer-invariants-over-fallbacks.md
(9f771794) and the imbue verifier-integrity module (29081fda).
invariants over fallbacks.
Ranked by observed cost across the repo's history. Hashes are sample
evidence, not complete lists.
| Rank | Class | Shape | Sample evidence | Standing guard |
|------|-------|-------|-----------------|----------------|
| RC1 | Silent failure / swallowed exceptions | except-continue, exit 0 on failure, dropped files | e0d1c464, 10b4b790, 52ae1459, fedb1c5b, 0d28a260, bfebb1ad, 7987649c, 89faaaf7 | Constitution rule 10 and the narrow-bare-except campaign |
| RC2 | py39 / host-Python import fragility | hooks crash under system Python | SB5, SB6 hashes | python39-compat.yml, AST test, meta_path tests |
| RC3 | PR-review rework churn | long fix-chains after review | tautological tests a94240e2, f1cbbcf1, 30e58586, 42f7ce84; AI-slop prose 2a039760, 62f598e9; stale wiring 204b927c, 332bcb75 | shift-left pre-commit guards, slop-check CI |
| RC4 | Unbloat over-deletion | import-graph-only deletion | SB3 hashes | markdown-reference scan, backup branches |
| RC5 | CI pin breakage | invalid or stale tool pins | SB11 hashes | check_pinned_versions.py, check_ruff_version.py |
| RC6 | Version drift | manifests and SKILL.md frontmatter out of lockstep | fan-out via plugins/sanctum/scripts/update_versions.py | sanctum:version-updates flow |
| RC7 | Fallback over-classification | guessing fallback masks bad data | SB15 hashes | prefer-invariants-over-fallbacks rule |
These branches are superseded. Do not resume work on them. They stay
for archaeology only.
| Branch | Why it is dead |
|--------|----------------|
| attune-tasks-poc | Superseded. Its lineage spawned the reverted SB1 consolidation. |
| agent-coordination | 2026-03-17 experiment, superseded by conjure and egregore. |
| feature/knowledge-brain | Pre-1.0 prototype, superseded by memory-palace. |
| feat/slop-clean-before-post | Superseded by scribe Tier-5 patterns on master (509bffaf). |
The backup/unbloat-* branches (a dozen as of 2026-07-02) are
recovery snapshots and the institutional memory of RC4.
backup/unbloat-20260328 was the recovery point for SB3. Do not
delete them casually.
spent repairing review findings after the fact (estimate from the
2026-07 repo audit, exact count unverified). Response: shift
quality left into pre-commit guards so review stops being the
first gate.
one commit, 182 files, multi-commit recovery, CI repair.
outage, and the linter actively fought the fix until an AST
invariant test ended it.
What counts as a settled battle:
Format: copy the SB block shape. Five fields, all required: Symptom,
Root cause, Evidence (commit hashes, each verified with
git log --format='%h %s' -1 <hash> before you write it down),
Status, Lesson. Assign the next SB number. Add the class to the RC
table if it recurs.
Where the lesson must also land (this file is not the system of
record for policy):
[Learning] or [PR Finding] post, and thedecision journal (docs/tradeoffs.md, docs/lessons-learned.md,
append-only). See night-market-collective-memory.
.claude/rules/ through the pipeline in
night-market-research-methodology, subject to
night-market-change-control.
night-market-debugging-playbook.
night-market-operations.
night-market-change-control.
self-containment, hook import-safety): use
night-market-architecture-contract.
decision journal: use night-market-collective-memory.
Provenance below prints no MISSING lines.
and any override of a lesson is written down with a rationale.
verified commit hash.
skill (Discussions post or decision-journal line exists).
Compiled 2026-07-02 against repo v1.9.15, branch master history
(1,247 commits). Volatile facts: branch list, RC ranking, and the
costliest-three judgment reflect the repo as of that date. The ~140
fix-chain commit count for RC3 is an unverified estimate.
Re-verification commands:
# All cited hashes still resolve
for h in 054e2679 29961cd2 d89a55c7 2fcb256d bc318947 a3f11323 \
3f280334 b5f08bf7 d6c128f5 01a13e70 06b9b1db 18c9340d b0049fde \
709dafc9 45dd77ef 9bfc0a7a 3d22f02a 268cff89 666171c3 b6de71cf \
f81d89a5 25bf5a9d 4993273b a8c9e4e9 69fbd32c 9f771794 29081fda \
509bffaf e0d1c464 10b4b790 52ae1459 fedb1c5b 0d28a260 bfebb1ad \
7987649c 89faaaf7 a94240e2 f1cbbcf1 30e58586 42f7ce84 2a039760 \
62f598e9 204b927c 332bcb75; do
git log --format=%h -1 "$h" >/dev/null 2>&1 || echo "MISSING $h"
done
# Dead-end and backup branches still present
git branch --list 'backup/unbloat-*' attune-tasks-poc \
agent-coordination 'feature/knowledge-brain' \
'feat/slop-clean-before-post'
# Standing guards still in place
ls plugins/leyline/tests/test_python39_compat.py \
plugins/abstract/hooks/shared/hook_io.py \
scripts/check_pinned_versions.py scripts/check_ruff_version.py
rg -q "meta_path" plugins/gauntlet/tests/unit/test_challenges.py
rg -q "LLM_TIMEOUT_SECONDS < hook_timeout" \
plugins/herald/tests/unit/test_double_shot_latte.py
Take athola/night-market-failure-archaeology from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.