feat(hooks): publish_overrides — a per-PATH policy that overrides the vault's (#10) - #14
Merged
Conversation
… vault's (#10) The publish policy is per VAULT (`publish:` in vault.yaml); the state that produces the Stop nudge is per DOC. So when one doc cannot publish — because the server REJECTS it, not because nobody tried — the only lever was `publish: manual`, which silences every other doc in the vault too. What is left is a nag that fires every session with no action available, which trains the reader to ignore the channel. The orphan bucket already decided this case ("clear either way -> no re-nag"); this is the missing other half. name: atelier publish: prompt publish_overrides: manual: - BITACORA.mdx # why this path is listed goes right here Absent => today's behavior, byte for byte. Two properties are the point: it is EXPLICIT (someone typed the path, and by convention the reason beside it) and it EXPIRES BY ITSELF (delete the line when the block lifts). No implicit suppression. The shape is narrow, and every narrowing fails toward KEEPING THE NAG: exact paths relative to the VAULT ROOT (the dir holding vault.yaml — the same root the CLI walks up to for a slug, so the two cannot drift); no globs (an entry with * ? [ ] { } ! matches nothing, because one line must not silence a subtree nobody enumerated); all three policy words accepted as keys, an unrecognized key ignored; block style only. `vault_policy()` is untouched. `doc_policy()` sits beside it, resolves an override and otherwise DELEGATES — so non-regression is structural, not a thing we test for. stop.sh changes on one line (the bucketing) plus the comment above it. Tests: 83 -> 100 pass, rc 0. Every arm is a PAIR — the listed path that goes silent and a path in the SAME session that must still nag — because a fix that silences every arm has deleted the feature rather than repaired it. Both mutants killed: forcing delegation turns arm (a) RED (the listed doc nags), forcing `manual` turns arm (b) RED (silence where exactly 1 was required). Closes #10
`publish_overrides:` accepts `manual` / `prompt` / `auto` and IGNORES anything else.
It did — flatly. One level deeper it did not:
publish_overrides:
weird:
manual:
- BITACORA.mdx # silenced, under a key that was supposed to be ignored
Nothing tracked nesting depth, so the inner `manual:` opened a list as if it sat at
the top of the block. Over-accepting a key here fails toward SILENCE — a doc nobody
published stops nagging — which is the one direction this file refuses everywhere
else. A key is now only a key at the indentation of the FIRST key in the block.
Its pair goes in beside the flat unrecognized-key arm: the nested entry silences
nothing while a top-level `manual:` in the same file still works, so the arm reads
exactly 1 rather than 0. Verified load-bearing — relaxing the depth check turns that
arm RED with `<silence>`, the precise failure it exists to catch.
Tests: 100 -> 101 pass, rc 0.
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.
The hole
publish:invault.yamlis per VAULT. The state that produces the Stop nudge is perDOC. So when one doc cannot publish — because the server rejects it, not because
nobody tried — the only lever was
publish: manual, which silences every other doc inthe vault too. What is left is a nag that fires every session with no action available,
which is how a channel gets trained into being ignored.
This repo already decided that case in the orphan bucket (
stop.sh, "clear either way →no re-nag"). This is the missing other half.
The shape
vault.yamlgains an optional block. Absent ⇒ today's behavior, byte for byte.Two properties are the point: it is explicit (someone had to type the path, and by
convention the reason beside it) and it expires by itself (delete the line when the
block lifts). No implicit suppression, ever.
Every narrowing fails toward keeping the nag:
* ? [ ] { } !)publish_overrides:{manual: [a]}vault_policy()The vault root is the directory holding
vault.yaml— the same root the CLI walks up towhen it derives a slug. One rule in both places or they drift.
Structure
vault_policy()is untouched.doc_policy()sits beside it, resolves an override andotherwise delegates — so non-regression is structural rather than a property we have to
keep testing for.
stop.shchanges on one line (the bucketing) plus the comment above it.autois an accepted key, so a listed path can newly reach the bucket that shells outto
basalt publish. That bucket's logic is unchanged; only which files can reach it, andonly when someone wrote the path explicitly. It has its own test, plus the twin proving an
unlisted path in the same vault is never auto-published.
Measurement
bash plugins/basalt/hooks/tests/run.sh→ rc 0, pass 83 → 100.Every arm is a pair: the listed path that goes silent, and a path in the same session
that must still nag. The sharpest one is
#10 (b)— override listsBITACORA.mdx, sessionedits it and
README.mdx, must nag for exactly 1.0means the vault got silenced(feature deleted);
2means the override did nothing.Falsifiable-instrument gate — both mutants verified by effect before their verdicts
were read:
doc_policyto delegate alwayslisted=prompt(override dead)doc_policyto returnmanualunlisted=manual(silence unconditional)<silence>where exactly 1 was required; 35 arms failAlso covered: all three vault policies with no
publish_overrideskey (unchanged),./x.mdxnormalization, a trailing# reasoncomment, block termination at column 0, andboth halves of the suffix trap — a bare
x.mdxdoes not matchnotes/x.mdx, and anidentically-named doc in a different vault is not silenced.
bash scripts/validate-skills.sh→ rc 0. Thevault.yamlexample inskills/basalt/references/cli-path.mddocuments the new key.Closes #10