fix(wiki,knowledge-flush): enforceable prohibition rule, disjoint routing scopes, flush concurrency (#36 #37 #77) - #93
Merged
Conversation
Replaces the "don't outside Instead-of" judgment call with a ported, corpus-validated parser (scripts/wiki-lint-prohibitions.js): a bare prohibition alone in its directive item (table cell or bullet) is a violation; one paired with a replacement or mechanism, or living in an Instead-of row, is compliant; a bare 2-word cell is an undecidable blind spot surfaced at info (new check 11), never error. Closes #36. 0 violations / 61 directives on wiki/, matching the reference probe at .orchestration/evidence/i36-rule-probe.js. AGENTS.md rule 3 and wiki-lint check 2 restated to match, in the same words, both naming the script. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_0199ew7RNxbFAiiWaegbXuDP
Routing probes 6 and 7 found two AMBIGUOUS pairs where two domains claimed
near-identical scope, forcing a router to open both pages to decide. Give
each pair a disjoint predicate plus mutual inline cross-pointers so the
index "load when" line alone resolves it.
- Doc-gate cluster (testing/quality <-> qa/document-verification): split on
mechanism ("does my check discriminate?") vs acceptance ("is passing the
gate enough to accept the deliverable?"). qa/spec-document-gates no
longer claims check-authoring or unwritten-target gate patterns.
- Flaky pair (testing/flaky <-> debugging/concurrency): split on what the
unreliable thing is - a test in your suite vs the system itself - after
an initial reproduction-state axis proved undecidable from a bare symptom
statement (probe 7) and was revised mid-implementation.
- Two minor route fixes: INDEX/backend LLM phrasing no longer attracts
ML-training queries; databases index cross-points to the backup/restore
page.
Closes #37.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01FU4PzRNVigcSwJCKxDTYrj
…en lock + queue claim Close #77. The manual /dev-loop:knowledge-flush skill and the hooks/auto-flush.sh Stop hook drain the same insight queue but had no mutual exclusion, and the hook released its lock with a bare `rmdir` that can delete the next holder's lock after a TTL expiry. - scripts/flush-lock.sh: new owner-token mkdir lock (acquire/release/holder), 900s TTL with pid-liveness stale reclaim, fail-fast on a held lock, and re-entrant acquire for the same run id (refreshes the epoch instead of treating a hook-spawned child session as a foreign holder). - hooks/queue-claim.js: claim/release queue rows by run id (list/claim [--max N]/release), 3600s claim TTL, atomic tmp+rename rewrite, dedupes on harvest.js's existing "hash" key, never touches .processed.jsonl or drops an unparseable line. - hooks/auto-flush.sh: acquires/releases through flush-lock.sh instead of the bare rmdir; PENDING count already excluded claimed rows, now documented. - skills/knowledge-flush/SKILL.md: new step 0 acquires the lock before the checkout's hard-reset step in step 1, and generates one run id explicitly threaded through every later flush-lock.sh call (each step runs in a fresh shell, so nothing survives via export); step 2 claims rows before ingesting; step 5 retires only claimed rows and releases unclaimed ones. - README.md/README.ko.md: document the two new TTL knobs in the existing auto-flush env-var block. tests/flush-lock.bats (14) and tests/queue-claim.bats (13) cover the age/pid-liveness reclaim matrix, re-entrant vs. foreign run-id acquire, non-owner release refusal, malformed/empty state, .processed.jsonl exclusion, and --max truncation. tests/harvest.bats (12) unaffected. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01RzpAVVUM6BrhzsecWJ4uZ4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #36
Closes #37
Closes #77
Three independent issues, implemented in parallel worktrees and merged locally
after review. 26 files, +1142 / -60.
#36 — wiki-lint check 2 is now mechanically enforceable
Check 2 flagged 147 prohibition phrases with zero true violations
(
plans/wiki-audit/findings/structure.md), so it was permanent manual-reviewnoise that hid nothing.
The rule was validated against the live corpus over four iterations before any
code was written. Earlier formulations were rejected by measurement, not taste:
never("references never released")## Sourcescitations quote prohibitionsFinal rule: a prohibition clause (≥3 words, starting with
don't/do not/never/avoid/must not) must share its directive item —a table cell or a bullet — with either the replacement action or the
mechanism that makes it true.
## Sourcesis out of scope.Corpus practice pairs prohibitions with a reason more often than with an
alternative action (
Never retry — the request itself is wrong; the same bytes fail again), which the oldAGENTS.mdrule 3 would have failed. The new rulepermits it.
scripts/wiki-lint-prohibitions.js— exits 0 clean / 1 violations / 2 bad dirpassing and failing rather than only ever returning 0
| Unknown key | Never read |vs| Timeout | Never retry |)are undecidable by shape, so they surface as new check 11 at
info#37 — disjoint routing scopes for two ambiguous pairs
Routing probes 6 and 7 (
plans/wiki-audit/findings/routing.md) were AMBIGUOUS:two concerns each claimed verbatim by two domains.
testing/qualityownsauthoring and validating the check;
qa/document-verificationowns whetherpassing it is enough to accept the deliverable.
testing/flaky; the system itself →debugging/concurrency.The flaky predicate was first written as "do you have an on-demand
reproduction?" and the independent auditor rejected it twice — correctly. Probe
7's wording ("an intermittent CI test failure that passes on retry") does not
state whether a reproduction exists, so that predicate is undecidable at the
routing gate, which is exactly where it must be decided. The subject of the
failure is always stated in the symptom, so subject is the decidable axis.
Both probes re-run UNIQUE from index lines alone. Also fixes the
INDEX.mdbackend LLM phrasing (a weak attractor for ML-training queries) and adds a
databases→backup cross-pointer.
#77 — knowledge-flush no longer races itself
The manual skill and the
auto-flush.shhook drained one queue into competingPRs and reset each other's checkout. Fixed on both axes the issue identified as
complementary — and the bundled wiki independently prescribes the same pairing
(
distributed-locks: "the lock alone cannot provide this";scheduled-job-overlap: "prevention lowers the probability; idempotency removesthe damage"):
scripts/flush-lock.sh— one owner-token lock shared by both entry points.mkdiris the primitive becauseflock(1)is util-linux-only and absent onmacOS. Release is delete-if-token-matches; reclaim needs TTL expiry and a
dead pid.
hooks/queue-claim.js— per-run claim of queue rows, so even a concurrent pairproduces disjoint PRs. Atomic tmp+rename; an unparseable line is carried
through verbatim, never dropped.
This also removes a live bug:
auto-flush.shreleased its old lock with a barermdir, the exact anti-pattern that deletes the next holder's lock after a TTLexpiry.
Two blockers found in review and fixed before merge, both from the run id being
computed per process:
and got exit 3 — silently killing the whole auto-flush path.
acquireis nowre-entrant for the same owner; a foreign run id still gets 3.
releasecomputed a new run id, was refused, and leaked the lock for the full900s TTL.
Verification
wiki-touching tasks do not break each other
foreign acquire 3, cross-shell release 0, no leak
Every verification command was re-run by the coordinator rather than taken from
the worker reports.
Not included
#38 (wiki category seeds) and #75 (orchestrator-skill pattern) were in the
approved split but not implemented; #38 collides with in-flight work on the same
domain indexes. Both stay open.