Commit Graph

447 Commits

Author SHA1 Message Date
afbeaff56b docs(agents): correct the ADR-0020 gate counts after the git retrofit
Descriptions over the FAIL tier 19 -> 10, bodies 7 -> 2. This line is
always-loaded context, so a stale count misleads every session.
2026-08-30 13:14:00 +00:00
3cd3f33706 refactor(pc-author): retrofit to the ADR-0020 context contract
Description 475 -> 213 chars, body 680 -> 212 words. Create and modify
become self-contained flow files behind a dispatch table, since the two are
mutually exclusive on whether the config already exists.

Passed its clean-context audit with no must-fix findings.
2026-08-30 13:10:53 +00:00
15ff7417b9 refactor(pc-run): retrofit to the ADR-0020 context contract
Description 477 -> 211 chars, body 736 -> 367 words. Install, autoupdate,
and clean become flow files behind the Route table.

The audit found no route for 'hooks aren't running': the only pointer to
failure-patterns.md sat inside the failure path, but when hooks never fire
the manual run succeeds, so the request fell to the ambiguity default and
was masked. Restores the disclosure that install -f is not reversible by
uninstall.
2026-08-30 13:10:53 +00:00
7cb8e95379 refactor(git-history): retrofit to the ADR-0020 context contract
Description 450 -> 266 chars, body 1044 -> 462 words. The bisect procedure
moves to references/bisect.md.

The boundary clause read 'not writing or rewriting commits', which
disclaimed the cherry-pick and revert this skill's own Step 3 executes; it
now excludes authoring and rebasing only. Adds 'backport' so cherry-pick is
reachable by natural language at all, accepting 266 chars against a 250
soft target and a 400 ceiling.
2026-08-30 13:10:53 +00:00
261e5b5491 refactor(git-submodules): retrofit to the ADR-0020 context contract
Description 480 -> 248 chars, body 1011 -> 347 words. The single
submodules.md splits into setup-and-update, urls-and-config, and removal.

Restores three regressions the first pass introduced: 'repointing' as the
trigger for the URL branch, which had none while the boundary clause
steered those queries to git-remotes; clone and absorbgitdirs in the output
enum, which dispatch still routed to; and status --cached, the flag that
makes the pre-commit pointer gate verifiable.
2026-08-30 13:10:53 +00:00
3c74beb280 refactor(git-workflow): retrofit to the ADR-0020 context contract
Description 566 -> 249 chars, body 644 -> 398 words, Gotchas 12 -> 2. The
eight organisational hard rules move to references/hard-rules.md.

Its load trigger enumerates operations rather than rule topics: the first
draft keyed on 'commit message form', which left the atomicity and
working-state rules unreachable when a caller supplied a conventional
message. Also promotes the destructive-op confirmation ahead of the
orchestrator invocation, which it previously followed.
2026-08-30 13:10:53 +00:00
38eb0745b7 refactor(git-remotes): retrofit to the ADR-0020 context contract
Description 582 -> 237 chars, body 1217 -> 290 words. The single remotes.md
splits into config, fetch, push, and pull flow files.

Restores the confirm: true token to the force-push gate -- it is the git
plugin's cross-skill contract, gated on by git-orchestrate and git-branches.
Moves push.md's worked example off main, which the skill's own Step 1
refuses, and restores the never-bare---force directive.
2026-08-30 13:10:53 +00:00
3dd5387671 refactor(git-worktrees): retrofit to the ADR-0020 context contract
Description 592 -> 248 chars, body 756 -> 515 words, Gotchas 8 -> 4.

The audit found the dispatch table had no row for a worktree on an
existing local branch, so that request fell to the adjacent -B row, which
resets the branch to HEAD and discards its commits. Non-destructive create
is now the first row and -B names its own destructiveness. Adds the missing
lock/unlock row and repair's run-from constraint.
2026-08-30 13:10:53 +00:00
0fde892f20 refactor(git-branches): retrofit to the ADR-0020 context contract
Description 612 -> 273 chars, body 1124 -> 457 words. Branch patterns,
operations, merging, comparison, and the orchestrator contract move to
references/.

Corrects rebase routing in four places: this skill sent rebase to
git-history, which carries no rebase content and disclaims it. Rebase is
git-commits'; cherry-pick and revert stay git-history's. Drops a Step 3
gate on a rebase flow this skill does not have.
2026-08-30 13:10:53 +00:00
f3b4860e14 refactor(git-commits): retrofit to the ADR-0020 context contract
Description 724 -> 214 chars, body 1102 -> 343 words, Gotchas 12 -> 3.
Create, rewrite, and cherry-pick flows move to self-contained references/
files behind a dispatch table.

The audit caught that moving the secret scan into the create flow left the
amend/squash path with no check in its loaded context; it is now a gate
common to every flow. Also re-homes the interactive-rebase reflog warning
git-history dropped, since this skill owns rebase.
2026-08-30 13:10:53 +00:00
bbc73008a3 chore(gitea): regenerate the flat content mirror after the ADR-0020 retrofit
Generated output, not authored content: scripts/sync-plugin-content.sh --all.
Claude Code has no .apm/ awareness, so this compiled mirror must track .apm/ or
the check-plugin-content-sync pre-push hook reports drift.

Deferred to a single commit at the end of the wave on purpose. sync_dir runs
rm -rf before every copy, so running it while seven agents were editing the
same plugin would have raced them; agents were told not to sync for that reason.

Refs #99
2026-08-30 12:42:20 +00:00
bedbd1d872 refactor(gitea-workflow): retrofit to the ADR-0020 context contract
Description 1012 -> 347 chars, body 582 -> 170 words, Gotchas 3 entries -> 1 at
22.9% of body. Clears the description FAIL and all four Vale CompositionNote
errors -- the last carriers in the corpus, so that rule now fires nowhere.

Cut the 'human-facing entry point and router' architecture note, the /gitea
migration history and the six-skill composition list; all were already in the
README or the routing table.

Split three mutually exclusive flows into a dispatch table keyed on invocation
shape, each branch self-contained in references/: status-checkin.md,
number-resolution.md, skill-index.md. Report stays in the body as the gate
common to every branch; each branch's own format moved to its file. The old
Step 1-4 numbering presented three alternatives as a sequence.

The description grew from an intermediate 283 chars on purpose: that draft had
dropped flow 3's trigger entirely, leaving the domain-routing index -- a third
of the skill -- reachable only through a tail clause whose grammatical subject
was the request rather than the skill. Both gates were green over that.

Boundary clauses are one arrow per target, so both resolve (#107: the resolver
extracts only the first target per clause and reports 1 of 1 on a clause naming
two). The local-git exclusion keeps its wording but drops the route to
git-workflow, which would not resolve in a gitea-only install.

Known residual: the dispatch conditions are stated twice, as a table and as
literal conditionals. That is #109 -- body-discipline.md mandates the literal
form while the ADR's cited exemplar, apm-workflow, uses a bare table plus one
summary line. Fixing it here would settle that contradiction in a skill rather
than in the spec, so it rides with #109.

Refs #99, #107, #109
2026-08-30 12:42:04 +00:00
b8c36c36f6 docs(agents): correct the ADR-0020 gate counts to measured state
The bullet is always-loaded context, and all three of its numbers had gone
stale as the issue #99 retrofit landed. Measured now: 19 of 39 descriptions and
7 of 39 bodies over their FAIL tier, down from 26 and 9; one dangling routing
target left (research -> neuledge-context), down from two.

Kyberforge.CompositionNote fired 10 errors across four gitea-* skills and now
fires nowhere -- those four were the only carriers and all four have been
retrofitted. The 'check both gates' advice stays: skill-size-check still does
not cover the Vale half, and any new description can reintroduce the rule.

Refs #99
2026-08-30 12:35:48 +00:00
23b843a311 test: drop the gitea-labels pin now the retrofit removed that target
tests/test-adr0020-targets.sh pinned the corpus dangling set as exactly
{gitea-labels, neuledge-context} and tests/test-skill-size-check.sh probed both
individually. The gitea-issues retrofit cut the composition sentence whose
'>'-folded scalar produced 'gitea-labels- milestones', so that target no longer
exists and both suites went red.

EXPECTED_DANGLING is now {neuledge-context} and the gitea-issues probe is
removed rather than skipped, per the rule the probe file states about itself: a
probe whose fixture has been retrofitted is a pin that needs updating, not an
assertion-free pass counted in the totals.

The exact-set assertion stays. An empty expected set is still valid and still
pins that no new dangling target appeared -- which is what it becomes once
research is retrofitted. Both loops carry a shellcheck SC2043 waiver for the
same reason: one entry is the expected steady state, not bad quoting.

Refs #99
2026-08-30 12:34:24 +00:00
37382cb72a refactor(gitea-labels-milestones): retrofit to the ADR-0020 context contract
Description 835 -> 214 chars, body 669 -> 426 words, Gotchas 8 entries/63% of
body -> 3/20.4%. Clears the description FAIL, all three Vale CompositionNote
errors and both Gotchas suggestions. 63% was the worst Gotchas ratio in the
corpus.

Cut the composition sentence to README -- it changes no routing decision and an
agent picks this skill because the user asked about labels, not because two
other skills call it. Cut the capability enumeration; 'list, create, edit,
delete' decompose 'reading or writing' and add no trigger.

Boundary clauses are now one arrow per target. The resolver extracts only the
first name per arrow clause, so the previous '-> gitea-issues / gitea-prs' left
gitea-prs neither dangling nor checked while validate.sh reported 1 of 1. Now
2 of 2.

Makes org-scoped label resolution executable. The org label pool was reachable
in principle -- four *_org_label* methods, and a claim to own name-to-ID
resolution -- but list_org_labels takes org, and Step 1 derived only owner and
repo, so both resolution procedures stalled at the fallback. Fixed once at the
identity step rather than per-procedure. get_user_orgs is outside allowed-tools,
so the failing call is the discriminator: a failure means the owner is a user
account with no org pool, which is an answer, not an error.

Corrects a Gotcha that was false for create_repo_label/create_org_label and
collided with the literal tool name label_write. Same false claim removed from
README.

Refs #99
2026-08-30 12:29:18 +00:00
78015893d4 refactor(gitea-issues): retrofit to the ADR-0020 context contract
Description 827 -> 182 chars, body 902 -> 584 words, Gotchas 7 entries/43% of
body -> 4/23.1%. Clears both size FAILs, the dangling-target FAIL and the Vale
CompositionNote error.

The dangling 'gitea-labels' target is gone with the composition sentence that
carried it -- a YAML fold artifact, not a typo: the '>'-folded scalar joined
'gitea-labels-' and 'milestones' across a line break, leaving the name terminal
and danglable. Both boundary names now sit whole on one source line each, and
both resolve.

Cut the second trigger register, the seven-verb capability enumeration, the
issue_write implementation detail and a gitea-branches boundary that defended
nothing. Two Gotchas deleted as spec restatement carried in references/, one as
a paraphrase of the step below it.

Closes a capability hole rather than papering over it: gitea-labels-milestones
routes label application here and has no issue_write, but no dispatch row
existed for add/replace/remove/clear_labels or get_labels. Both rows added.
The label ID/name Gotcha is now stated per method -- issue_write takes IDs,
list_issues and search_issues filter by name, issue_read 'get' returns names
but 'get_labels' returns full objects with IDs.

Drops a stale quotation of gitea-labels-milestones' description from
references/enrichments.md; that string went with its composition note.

Refs #99
2026-08-30 12:28:54 +00:00
0079f3508c fix(gitea-prs): correct reference drift against gitea-mcp v1.7.0
The reference files were last verified against v1.3.0 -- references/sources.md
still said so. PR #106 re-verified the write side only, so three defects had
accumulated on the read/review side. All three reproduced against the deployed
server before being fixed; get_gitea_mcp_server_version reports v1.7.0.

- reviews.md forbade review_comments on the "get" response and directed callers
  to review_scomments, which does not exist. The upstream slim.go typo was
  corrected; a live pull_request_read on PR #106 returns "review_comments":1 and
  no review_scomments key. review_comments is an integer count, not comment
  objects -- distinct from the get_review_comments method. Also fixed in
  pull-requests.md's response-shape list.
- pull_request_review_write grants seven methods; only four were documented.
  reply_comment, resolve_thread, unresolve_thread and the comment_id parameter
  had zero mentions anywhere in the skill. Documented from the schema, in a
  Comment threads section kept outside the numbered review state machine --
  they are not lifecycle states.
- review_id was documented as required for get_review_comments. It is optional;
  omitting it lists every inline comment on the PR. Confirmed behaviourally:
  get_review without it errors, get_review_comments without it returns [].

sources.md now records v1.7.0 as the last-verified version, so the next reader
knows what these files were checked against.

Refs #99
2026-08-30 12:21:11 +00:00
d578d6b2f2 refactor(gitea-prs): retrofit to the ADR-0020 context contract
Description 709 -> 161 chars, body 683 -> 353 words, Gotchas 8 entries/56% of
body -> 2/24.9%. Clears the description FAIL and both Vale CompositionNote
errors.

Fixes the three stale claims recorded on issue #99, all re-verified against the
deployed gitea-mcp schema during review:

- The description no longer advertises 'reviewers' as an update capability.
  editPullRequestFn never reads reviewers or team_reviewers; only
  add_reviewers/remove_reviewers do.
- milestone is now marked honoured on "update" only, in the Gotcha, the body
  and the dispatch table's create row. On "create" the server discards it and
  omits the key from the response, so the drop is indistinguishable from never
  passing it -- and labels DOES apply on create, so labels landing is no
  evidence the milestone did. The old text told callers to resolve a milestone
  before any write, wasting the lookup on create.
- The superseded un-draft workaround is gone. "update" with draft:false and no
  title makes the server strip the prefix itself, including [WIP],
  case-insensitively -- carried by references/pull-requests.md, corrected in
  PR #106.

The 22-row tool/method table becomes a 5-row dispatch table; all 20 operations
it named remain reachable, including update_branch and the reviewer methods.

Refs #99
2026-08-30 12:10:21 +00:00
d5954d3d99 refactor(gitea-files): retrofit to the ADR-0020 context contract
Description 787 -> 263 chars, body 922 -> 302 words, Gotchas 9 entries/69% of
body -> 3/24.8%. Clears both size FAILs and both Gotchas suggestions.

Deleted the second trigger register outright -- ~300 chars re-quoting the same
six verbs as user phrasings, which ADR-0020 names this skill for specifically.

Split the body on the read/write boundary: one invocation cannot both read and
write, so a dispatch table is mandatory. Six operations collapse into two flow
files rather than six -- create/update/delete share one tool pair and one
SHA-first lifecycle whose preamble would otherwise be triplicated, and the three
read tools share ref selection plus a 'neither listing is a SHA source'
comparison that only exists between them.

references/examples.md removed; all eight of its content blocks and all nine
named parameters carry into references/writing.md, verified against git HEAD.
Two deltas are corrections: the repo tree is now ruled out as a SHA source, and
reusing a SHA captured earlier in the conversation is now forbidden.

Four Gotchas relocated to the flow file that needs them; two promoted to gates
(SHA-as-concurrency-token opens writing.md; owner/repo became ## Inputs).

Refs #99
2026-08-30 12:09:52 +00:00
ee812699a4 refactor(gitea-branches): retrofit to the ADR-0020 context contract
Description 688 -> 282 chars, body 435 -> 293 words, Gotchas 5 entries/54% of
body -> 3/23.5%. Clears the description FAIL and the Gotchas suggestion.

Cut the second trigger register (six re-quoted user phrasings) and the capability
enumeration; both moved to a new Boundaries section in the skill's own README.
Kept all three boundary clauses -- git-branches, git-history and gitea-prs each
defend a real activation steal, and gitea-prs is now the only guard on the
branch/PR collision in either direction since gitea-prs's own retrofit narrowed
its boundary to issues. Written as one arrow per target: the resolver extracts
only the first name per arrow clause, so conjoined targets go unchecked.

Two Gotchas deleted -- one paraphrased the step below it (its non-obvious half,
the get_me/list_my_repos token-scope block, was folded into that step), the other
is carried in full by references/branches.md:40-52.

Repoint two reference pointers the rename broke: branches.md and commits.md named
Gotchas by titles this retrofit changed. Now named by stable descriptors.

Refs #99
2026-08-30 12:08:38 +00:00
dfacf051a8 refactor(gitea-releases): retrofit to the ADR-0020 context contract
Description 500 -> 211 chars, body 676 -> 462 words, Gotchas 5 entries/41% of
body -> 3/21%. Clears the description FAIL and both Gotchas suggestions.

Cut the second trigger register (the re-quoted user phrasings), the doubled
capability enumeration across releases and tags, and the gitea-issues/gitea-prs
boundary, which defended against nothing -- neither was going to win a release
request. Kept the indirect trigger and the one real near-miss, gitea-branches.

Releases and tags are one flow, not two: 'delete the release and its tag' is a
single invocation that takes both branches, which disqualifies mutual
exclusivity, so no dispatch split. Two Gotchas moved to references/ behind
explicit triggers; one deleted as a paraphrase of the step below it.

Refs #99
2026-08-30 12:06:37 +00:00
ef3e981eac docs(context): record that hand-invocation blocks skill-to-skill routing
The Hand-invoked skill entry covered listing visibility and preload tax but not
invocability. Measured: disable-model-invocation: true hard-blocks the Skill
tool, not just the model-visible listing, so a `Call `x`` step in another
skill's body stops working the moment x takes the flag.

ADR-0020's 'Invocation as a design axis' verified only the visibility and slash
directions. Without this half, marking grill-with-docs hand-invoked -- one of
issue #99's four named candidates -- would silently break forge Step 1, which
calls it, plus three other inbound routes.

Refs #99
2026-08-30 11:54:26 +00:00
5f984ce34a chore(apm): refresh lock after SessionStart update
The SessionStart hook found six packages behind the remote default branch and
ran apm update. Committing the resulting lock separately so it does not sit in
the ADR-0020 retrofit diff.
2026-08-30 11:54:18 +00:00
0e91a3ae66 Merge pull request 'fix(gitea): correct which pull_request_write params apply on create' (#106) from fix/gitea-prs-create-drops-params into main
Reviewed-on: https://git.dev.rkdr.net/Defame1297/holocron/pulls/106
Reviewed-by: Defame1297 <gitea@rkdr.net>
2026-08-17 20:33:56 +00:00
967d3ade25 fix(gitea): document the remaining create/update parameter asymmetries
Follow-up to the review of #106, which found four parameter claims the
first pass left wrong or missing. All four verified against gitea-mcp
v1.6.0 source before changing anything.

`remove_deadline` is dropped on "create" like the others, but the new
Gotcha enumerated a closed list that omitted it — so the paragraph
contradicted its own opening sentence. The list is now open ("including")
and the parameter carries the same "update" only marker as its neighbours.

`base` is settable on "update": editPullRequestFn reads it and retargets
the PR onto a different base branch. The file documented it as required
for "create" and said nothing else, hiding a real capability. This one is
under-claiming rather than over-claiming, but a file whose subject is
which parameter applies to which method is the place to fix it.

applyDraftPrefix strips two prefixes, `WIP:` and `[WIP]`, matched with
strings.EqualFold, while only "WIP: " is ever added. The un-draft
correction said "the prefix" singular, which understates what a caller
can hand it.

README.md bundled `reviewers` and `milestone` into "creating and
updating". Capability prose rather than a parameter contract, so not
strictly false, but it is the same conflation that produced the original
bug and it is not behind any gate.

Not addressed here: SKILL.md's description still advertises updating
reviewers, its draft guidance still prescribes the manual workaround, and
its milestone-resolution instruction carries no method qualifier — so an
agent working from SKILL.md alone can still reach the failure mode. Those
edits trip skill-size-check and the Vale prefilter, pulling in the
ADR-0020 retrofit; tracked on #99 rather than done silently here.

Refs: #104
Refs: #99

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETxbGFetkbJQBHsx442Brt
2026-08-17 17:29:06 +00:00
4c9d2d7751 fix(gitea): correct which pull_request_write params apply on create
The gitea-prs reference documented `milestone` as "settable on both
"create" and "update"". It is not: `pull_request_write method: "create"`
accepts the parameter, returns no error or warning, and discards it.

Verified against the gitea-mcp v1.6.0 source rather than by observation
alone. `createPullRequestFn` builds its `CreatePullRequestOption` from
owner, repo, title, body, head, base, draft, labels and deadline only —
so the drop is not limited to `milestone` as issue #104 supposed.
`assignee`, `assignees`, `reviewers` and `team_reviewers` are discarded
on create too, and `reviewers`/`team_reviewers` are discarded on
"update" as well; they are only ever read by "add_reviewers" and
"remove_reviewers".

Two properties made the original error easy to make and hard to catch,
so both are now written down next to the correction: `labels` sits
beside `milestone`, reads identically, and does apply on create; and
`issue_write method: "create"` honours `assignees` and `milestone`, so
the asymmetry is specific to pull requests.

While in the file, corrected the adjacent draft gotcha. It prescribed
reconstructing the un-prefixed title by hand to un-draft a PR;
`applyDraftPrefix` shows "update" with `draft: false` and no `title`
fetches the stored title and strips the prefix server-side.

Impact: documentation only, no behaviour change. Callers following the
old text silently created PRs with no milestone, assignee or reviewer.
Confined to references/pull-requests.md, so the ADR-0020 skill gates do
not apply and gitea-prs needs no #99 retrofit first.

Fixes: #104
Refs: #99

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETxbGFetkbJQBHsx442Brt
2026-08-17 16:58:56 +00:00
68e08c2413 Merge pull request 'docs: cut the every-session context set by 74%, and fix what the cut broke' (#105) from docs/slim-agents-md into main
Reviewed-on: https://git.dev.rkdr.net/Defame1297/holocron/pulls/105
Reviewed-by: Defame1297 <gitea@rkdr.net>
v2.0.1
2026-08-17 14:08:23 +00:00
d42f6368fe fix(docs): correct claims the first fix round asserted without measuring
Why: two blind verifiers re-ran the five preceding commits and found four
defects of the same class this branch exists to close -- a confidently stated
measured claim that does not survive re-measurement -- this time inside the
fixes themselves.

- AGENTS.md:41 still carried both phrasings c68e864 reports having corrected.
  `grep -rn repo-defined` returned exactly one hit repo-wide: that line, in the
  file every session preloads. 4d336bb edited the line directly above it.
- ADR-0021 asserted twice, in the section justifying that no gate is added,
  that the ADR-0020 validators "never open an apm.yml". All three open and
  yaml.safe_load it (skill-size-check.sh:342, both validate.sh). The conclusion
  survives -- none reads the description: key, and their globs are SKILL.md and
  *.agent.md only -- but the stated mechanism is falsified by one grep.
- architecture.md said the ADR directory holds 20 numbered ADRs; c7ba3d2 made
  it 21, and c68e864 audited that file for exactly this class of stale count.
  The number is dropped rather than corrected: `ls docs/adr/` is already the
  index, so a count in prose is a second thing to maintain.
- gates.md's new three-verdict table said `-> name` promotes an unresolved
  target to ERROR. Reproduced with fixtures: NAME_HYPH (skill-size-check.sh:543)
  requires a hyphen, so `-> gitea-prs` is checked and `-> triage` is not
  extracted at all, and the unicode arrow is never recognised. The SUGGESTION
  text advises that spelling, so taking its advice can silence the finding. The
  gap is now documented as a defect; nothing covers it, since the one arrow case
  in test-adr0020-targets.sh happens to use a hyphenated target.

Implementation notes:
- AGENTS.md:48's coverage claim is shrunk rather than chased. Restoring six
  glossary entries did not make it true: 12 more sampled terms are undefined,
  three of them (trigger/capability/boundary clause) used inside CONTEXT.md
  itself. It now says CONTEXT.md is the glossary and is not exhaustive.
- CONTEXT.md's output profile and near-miss entries are corrected against their
  sources. The first stated a false exclusion -- .github/plugin/plugin.json IS
  apm-generated; only the marketplace mirror has no profile. The second
  inverted its source's referent: description-quality.md defines a near-miss as
  a query, not a sibling skill.
- The strict-mode message named jq, which no suite guards on (`command -v jq`
  appears nowhere in tests/), while omitting python3/PyYAML, which three do.
- README's git and gitea bullets now name git-workflow and gitea-workflow.
  ADR-0021 leaves README the only inventory and architecture.md now points at
  it, so the two bullets that were short had to be completed.
- ADR-0018's 2026-08-14 correction is marked superseded in place. It asserted
  machine state in the present tense that its own 2026-08-17 note retracts.
- ADR-0021's remaining errors: six files -> four (measured from de84d1b), the
  wiki description's length 114 -> 96 chars, the codex self-contradiction, the
  cost argument overstating bumps already owed for any skill addition, and two
  claims about files this branch went on to edit.
- The "15 of 17 suites" figure is restored where I had removed it: it is a dated
  record of one incident, not a live count, and four sites now describe it the
  same way.

Impact: 16/16 pre-push hooks pass, suite 24 passed 0 skipped 0 failed. No
behaviour change; every edit is prose or a comment.

Refs: #105

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TmFqzpuExLJv3m114XVE9w
2026-08-17 13:18:55 +00:00
c68e864159 docs(spec): correct eight claims the trim carried into the new files
Why: the relocation into gates.md and architecture.md moved text faster than it
verified it, and a review found eight assertions that do not survive contact
with the repo.

- gates.md cited docs/research/examples/, which does not exist; the tree is at
  plugins/kyberforge/docs/research/examples/. The same wrong string survives at
  ADR-0013:98, where it originated, and is tracked separately.
- gates.md's description-budget arithmetic was built on 23,427, a figure
  ADR-0020 measured at f9b919d and pins there, and compared a name-inclusive
  total against a description-only ceiling. Dropped rather than re-measured,
  following the precedent this branch set for CONTEXT.md's token figure: a
  second live copy is a second thing to go stale.
- gates.md listed "every boundary-clause routing target must resolve" as a hard
  FAIL. skill-size-check.sh emits unresolved targets as SUGGESTION by default,
  promotes to ERROR only when terminal and either route-notated or corroborated
  by a resolving target in the same sentence, and reports INFO DID NOT RUN when
  no universe resolves. Verified with five fixtures; replaced with a
  three-verdict table.
- gates.md and README called `pre-commit run --hook-stage pre-push --all-files`
  the whole push gate. check-release-needed.sh exits 0 unless
  PRE_COMMIT_REMOTE_BRANCH is refs/heads/main, which only the real git hook
  exports -- its own header comment titles this a "Known gap".
- "repo-defined" was loose: the two meta hooks are also declared here, and what
  separates them is repo: meta from repo: local.
- architecture.md claimed `when:` appears in two of 39 skill sources. Exactly
  one SKILL.md carries it; the second hit is a META.md. The likely origin is
  skill-implementation-workflow.md:233, which claims META.md sits alongside
  every skill when one exists in the whole tree.
- architecture.md said core/AGENTS.md is "deployed beside" CLAUDE.md.
  deploy-manifest.sh sends them to ~/.claude/ and ~/.agents/ respectively; the
  relation is import, not adjacency.
- gates.md's see-also cited ADRs as bare stems where its neighbours use paths.

Implementation notes: architecture.md's closing pointer sent readers to the
published description "for what a consumer actually gets", which was true
against an enumeration and is not after ADR-0021. It now names the boundary
relationship and points at the skills tree and README for an inventory. README's
bin bullet gains caveman and zoom-out, since ADR-0021 leaves it the only place
an inventory lives.

Impact: 16/16 pre-push hooks pass. Deliberately not fixed here and tracked
separately: the 12 pre-commit-stage hooks gates.md does not document, its own
SentenceOpenerThereIs violation, and README's missing scripts/install.sh step.

Refs: #105

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TmFqzpuExLJv3m114XVE9w
2026-08-17 12:29:16 +00:00
c7ba3d2ccf chore(apm): retire skill enumeration from published descriptions
Why: enumerating a plugin's skills in its published description has now failed
three times in four days, the third time inside the correction for the second.

bb9158d (Aug 14) fixed core's description, which described bin's skills. That
failure was wrong content, not an incomplete list -- a syntactically perfect
four-item enumeration that belonged to a different plugin -- so enumerating
harder could not have caught it, and bb9158d's own fix replaced the enumeration
with a domain boundary. 65bac15 and de84d1b then cited that precedent while
doing the opposite, and the re-enumeration is itself incomplete: caveman and
zoom-out are unnamed in bin, git-workflow is unnamed in git despite 65bac15's
message claiming it was added, and gitea-workflow is unnamed in gitea. 23 of 27
skills named at the third attempt.

Nothing checks any of this. check-manifests.sh does not contain the string
"description"; apm audit --ci, apm pack --check-clean and
sync-plugin-content.sh --check all compare compiled output against apm.yml, so
their job is to propagate whatever it says byte-for-byte. The wiki claim passed
all fourteen pre-push hooks every day it was published. Enumeration also makes a
marketplace release the consequence of a directory appearing.

Implementation notes:
- ADR-0021 records the decision, the three failures, and why no gate is added:
  the check is one-directional, cannot see an invented capability, and a
  correspondence map would relocate the same per-skill maintenance one file over.
- bin 1.1.4 -> 1.1.5, git 1.3.4 -> 1.3.5, gitea 1.3.5 -> 1.3.6,
  marketplace.version 0.4.4 -> 0.4.5, all PATCH under per_package.
- apm.yml's top-level version: is restored to lockstep at 0.4.5. It has moved
  with marketplace.version in all eleven commits that ever touched the file
  until this branch left it at 0.4.2, and apm.yml's own comment records it as
  live and consumed by apm audit.
- git's boundary names the pre-commit hooks explicitly: pc-author and pc-run are
  not git operations, and a boundary drawn narrower than the contents is the
  same defect one level up.
- Regenerated with apm pack for the marketplace manifests and
  sync-plugin-content.sh --all for the per-plugin ones; both mirrors verified
  byte-identical.

Impact: consumer-facing. 16/16 pre-push hooks pass, suite green, generated diff
is 26 insertions and 26 deletions across 8 files with no incidental churn.

Refs: #105
ADR: 0021

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TmFqzpuExLJv3m114XVE9w
2026-08-17 12:28:55 +00:00
4d336bbf35 docs: stop the preloaded instruction set asserting machine state
Why: four defects in the files every session pays for, all introduced or left
behind by the trim.

AGENTS.md told agents the `<plugin>:` form still resolves "because user-scope
native installs were left enabled on purpose", and that a working namespaced
call "is not something to fix". That premise is false on this machine:
installed_plugins.json is empty, no enabledPlugins key exists in ~/.claude.json,
and ~/.apm/marketplaces.json is empty. ADR-0018 already reversed itself once on
this exact claim (Correction 2026-08-14) using that same enablement as its
evidence, so flipping the assertion again would be the third revision in three.
Both files now assert nothing about install state at all, which removes the
flip-flop surface instead of re-aiming it.

The other three are guard-rails whose instruction survived the trim while the
caveat that made it safe did not:
- The run-tests.sh line omitted --strict, so it named the one invocation that
  reports SKIPPED rather than failed when a dependency is missing. gates.md
  records this gate going green having verified 15 of 17 suites on a vale-less
  PATH. .pre-commit-config.yaml:70 already uses --strict for that reason.
- The .claude/settings.json prohibition lost its ADR-0019 exception, so an agent
  applying it literally would strip apm's own merged SessionStart entry and
  create the drift the rule exists to prevent.
- LESSONS.md still routed graduated rules to CONTEXT.md's Principles section,
  which this branch deleted.

Implementation notes: the six terms the trim dropped while AGENTS.md still
claimed CONTEXT.md glosses everything -- authoring root, content mirror, apm
package, output profile, near-miss, vacuous green -- are restored as one-line
entries per CONTEXT-FORMAT.md, sourced from architecture.md, gates.md and
skill-audit's description-quality.md rather than reworded. ADR-0018 gets a third
dated note recording the observation and the fact that the state has now been
described two ways, and its stale user-scope inventory is replaced by a pointer
to it; the decision it records is untouched. LESSONS.md:3 carried the identical
stale claim as :5 and is fixed with it.

Impact: preloaded context is now free of assertions about machine state.

Refs: #105

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TmFqzpuExLJv3m114XVE9w
2026-08-17 12:28:30 +00:00
36596598ef fix(tests): point the strict-mode dependency citation at README.md
Why: this branch moved the prerequisites list out of AGENTS.md into README.md
but left three references behind. The worst is run-tests.sh's --strict failure
message, which a developer is handed at the exact moment a push gate fails and
they need the dependency list: it named AGENTS.md, which no longer documents
vale, apm or jq anywhere. 56cc173 re-anchored this same class of citation in
.pre-commit-config.yaml, scripts/check-vale-style-sync.sh,
scripts/sync-marketplace-mirror.sh and tests/test-check-vale-style-sync.sh --
tests/run-tests.sh was missed, and it is the only one a human actually reads.

Implementation notes:
- run-tests.sh:262 (user-visible), run-tests.sh:16 (header rationale) and
  test-run-tests.sh:395 all now cite README.md's Prerequisites table, verified
  to name vale, apm, jq, python3/PyYAML and the claude CLI.
- Every assertion on this message greps for "a skip is a SETUP ERROR", which
  sits before the changed clause, so no test needed updating.
- test-vale-wrap.sh's bash 3.2 citation is corrected in the same pass: it
  credited LESSONS.md and the script headers, but LESSONS.md's only mention of
  3.2 is an aside inside an unrelated lesson, not a target declaration. It now
  cites scripts/lib/batch-run.sh and providers/claude-code/statusline-command.sh,
  which do declare it. The citation 56cc173 replaced was already false, so this
  finishes a half-fix rather than correcting a regression.

Impact: forced the strict-failure path with vale removed from PATH and confirmed
the corrected message printing -- 21 passed, 3 skipped, exit 1. Full suite with
vale present: 24 passed, 0 skipped, 0 failed.

Refs: #105

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TmFqzpuExLJv3m114XVE9w
2026-08-17 12:28:11 +00:00
b1ea14df3e fix(scripts): make the mirror DRIFT fix line safe to copy-paste
Why: bd2bf66 restored the `apm pack` guard-rail by appending it to the `Fix:`
command after `--`, which made the printed line stop being runnable. Pasting it
ran the script with ~24 stray argv entries: `${1:-}` became `--`, so CHECK
stayed 0, no shift occurred, and `[[ $# -eq 0 ]] || usage` printed usage and
exited 1. The user got a usage error from the tool meant to fix their problem,
and the mirror stayed stale.

The unquoted backticks around `apm pack` were a second hazard in the same line:
the paste command-substituted a real `apm pack` run before this script was ever
reached, so the first error a user saw came from apm, not from here.

Implementation notes:
- The runnable command now stands alone on its own line, and the rationale
  follows as a separate `Note:` echo.
- Backticks downgraded to single quotes; a line printed next to a
  copy-pasteable command must not contain shell metacharacters.
- The guard-rail text is otherwise preserved verbatim. It exists because apm
  ships no output profile targeting this path, so `apm pack` does not refresh
  it, and expecting it to is the drift this hook prevents.

Impact: reproduced the break on a scratch copy, then verified the fix by pasting
the printed command verbatim — exit 0, mirror synced, re-check clean.
tests/test-sync-marketplace-mirror.sh asserts only exit codes and file contents,
so nothing pins this message and it could regress silently; tracked separately.

Refs: #105

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TmFqzpuExLJv3m114XVE9w
2026-08-17 12:27:56 +00:00
de84d1b677 chore(apm): give bin a published description that describes it
Why: bin's marketplace description read "A place for things to be binned" — a
routing boundary sitting in the enumeration slot, phrased as a joke. It is what
a consumer sees in the marketplace listing for a plugin shipping eleven
substantive skills: research, write-docs, tdd, prototype, triage, diagnose,
improve-codebase-architecture, grill-me, grill-with-docs, zoom-out and caveman.

This is the same category error b0ef503 fixed for git and gitea, and the same
text bb9158d moved out of core's description in August — "triage, diagnosis,
architecture review" left core precisely because those skills live in bin, so
bin is where it should have landed.

Implementation notes: bin 1.1.3 -> 1.1.4, marketplace 0.4.3 -> 0.4.4, PATCH for
metadata under the per_package strategy. README's bin line mirrors the new
description. architecture.md's routing boundary is deliberately left as
"unsorted skills that have not earned a home yet" — that is still true, and it
answers a different question than the listing does.

Impact: consumer-facing. apm-pack-check-clean, check-plugin-content-sync,
check-marketplace-mirror-sync, validate-marketplace, validate-plugins and
apm-audit-ci all pass.
2026-08-17 10:33:25 +00:00
65bac15257 chore(apm): correct git and gitea published descriptions and regenerate
Why: both plugins' published descriptions named capabilities that do not exist
and omitted ones that do. `gitea` advertised wikis — no wiki skill exists and
`grep -ri wiki plugins/gitea/.apm/` is empty — while omitting gitea-branches and
gitea-files. `git` advertised pull requests, which are gitea's, while omitting
pc-author/pc-run, git-submodules and git-workflow. These are compiled into
plugin.json and both marketplace.json files, so they are published metadata, not
internal notes.

This is the same defect bb9158d fixed on `core` in August, so the fix follows
that precedent exactly: correct the package apm.yml and the root marketplace
entry together — fixing only the package manifest leaves it half-propagated,
since the root entry is what reaches the compiled marketplace.

Implementation notes:
- git 1.3.3 -> 1.3.4, gitea 1.3.4 -> 1.3.5, marketplace 0.4.2 -> 0.4.3, all
  PATCH for metadata under the per_package strategy at apm.yml:76.
- Regenerated with `apm pack` for the two marketplace manifests and
  `scripts/sync-plugin-content.sh --all` for the four per-plugin plugin.json
  files; `apm pack` alone does not touch those. `scripts/sync-marketplace-mirror.sh`
  refreshed the Copilot legacy mirror, which no apm profile targets.
- README's gitea line mirrors the new published description. The routing
  boundaries in architecture.md deliberately do not, since they answer a
  different question.

Impact: consumer-facing. Anyone reading the marketplace now sees what these
plugins ship. apm-pack-check-clean, check-plugin-content-sync,
check-marketplace-mirror-sync, validate-marketplace and apm-audit-ci all pass.
2026-08-17 10:13:31 +00:00
b0ef503485 docs: correct plugin scope, hook ordering and the setup gap
Why: the review found architecture.md's plugin table and README's plugin list
were both written by enumerating what happened to be in each plugin, so both
went stale immediately — README credited `git` with pull requests it has no
skill for, and both omitted `pc-author`/`pc-run`. bb9158d fixed this same class
on `core` in August and it recurred here, so the fix is to stop enumerating in
the place whose job is routing.

Implementation notes:
- architecture.md's table now states routing boundaries only, with a note saying
  so and pointing at each plugin's published apm.yml description for the actual
  inventory. Two boundaries are named explicitly: `core` vs `kyberforge` (kept),
  and `git` vs `gitea` — wire protocol against a local clone versus the forge's
  HTTP API, which is why git-branches and gitea-branches are not duplicates.
- The `git` row is widened to cover git hook tooling rather than moving
  pc-author/pc-run elsewhere. pre-commit manages .git/hooks/, so the placement
  was always right and the row was simply under-described.
- README's setup block had a comment where step 2's command should be. It now
  carries `pre-commit install -t pre-commit -t commit-msg -t pre-push`, verified
  against the three stages in .pre-commit-config.yaml and the three hooks in
  .git/hooks/. pc-run is still named, as the option rather than the only path.
- README:11 said each plugin carries agents, hooks and MCP servers. Only
  kyberforge ships hooks and only bin ships an MCP server.
- gates.md:30 claimed its hook list was in config order; it is grouped by
  concern, which is the better layout, so the claim is corrected to match.

Impact: docs-only. gitea's published description is corrected separately, since
that regenerates consumer-facing manifests.
2026-08-17 10:11:59 +00:00
bd2bf667c5 docs: restore two guard-rails the trim dropped
Why: 1929ffd and b9c7762 preserved every constant, hook ID and error string,
but two don't-re-litigate notes were lost. Both were guard-rails — they fired
from preloaded context, before the mistake. Restoring the sentence to an
on-demand spec doc restores the text without restoring the function, since an
on-demand file is opened after a plan is formed, not before.

Implementation notes: placed by when each note must fire, not by what it is
about.
- "Do not expect `apm pack` to refresh the .github/plugin/marketplace.json
  mirror" now lives in the DRIFT failure message of the script and hook that
  already catch that exact mistake. It costs no preloaded tokens, fires at the
  moment of the error, and cannot be missed. No test asserts on that message;
  --check and shellcheck both pass.
- Plugin self-containment has no gate that fires on it, so it goes in
  architecture.md's Plugin model beside "self-contained plugin units", stated as
  the constraint it is rather than a description, with the two consequences that
  make it load-bearing: the duplicated Vale styles (ADR-0014) and ADR-0020's
  constants copied into three validators.

Impact: the every-session set is unchanged — neither note returns to AGENTS.md.
2026-08-17 10:10:55 +00:00
ba7cec7672 docs(adr): amend ADR-0007 and ADR-0015 for the CONTEXT.md trim
Why: b9c7762 gave dated amendments to ADR-0013, ADR-0015 and ADR-0017, but two
pointers were missed. ADR-0007 cited the "Provider-agnostic issue tracker"
glossary entry, which the trim renamed to "Issue". ADR-0015 cited the "lint
plugin" entry, which the trim deleted outright — and ADR-0015 was amended for
its other CONTEXT.md pointer in the same commit, so this one was missed inside
an already-edited file.

Implementation notes: ADR-0007 gets a dated parenthetical matching the pattern
the other three carry, confirming the entry survived under a new name rather
than being dropped. ADR-0015's Considered-options parenthetical is re-pointed
at docs/spec/architecture.md's plugin scope table, which now carries the
repo-agnostic-versus-marketplace-specific argument the deleted entry held, and
its existing 2026-08-17 supersession note is extended to record that second
redirect in one place.

Impact: all four ADRs that referenced moved CONTEXT.md content now say where the
content went. No decision is altered.
2026-08-17 10:10:24 +00:00
56cc173f65 fix: re-anchor doc citations that the CONTEXT.md trim broke
Why: eight comments and one status note cited CONTEXT.md or AGENTS.md text that
b9c7762 and 1929ffd moved or deleted. All are inert at runtime, but they are the
rationale comments that tell the next maintainer why an assertion exists, and
they now name a file that no longer explains it.

Implementation notes: re-anchored by what the citation is for, not uniformly.
- Four sites quoted facts ADR-0013 owns — every rule is `level: error` with no
  ignorable tier (ADR-0013:59-70), and KyberforgeCopilot's `.agent.md`-only
  scope (ADR-0013:43-46). These now cite ADR-0013. ADRs are append-only here;
  the spec docs are refactored, which is what caused this rot.
- Two sites quoted the glob location-independence property, which no ADR owns.
  The quote was already inline and carried the full rationale, so the citation
  added a rot surface and no information — dropped, statement kept.
- sync-marketplace-mirror.sh's header attributed the mirror-not-a-profile fact
  to CONTEXT.md; the parenthetical beside it already carries the evidence, so
  the attribution is dropped rather than re-pointed.
- .pre-commit-config.yaml cited an AGENTS.md instruction that no longer exists;
  generalised to "the documented instruction".
- LESSONS.md:29 misquoted AGENTS.md's current session-start line.

Also corrects a pre-existing misattribution at tests/test-vale-wrap.sh:454:
AGENTS.md has never named bash 3.2 as a repo target (`git log -S'3.2'` on it is
empty). LESSONS.md and the script headers do.

Impact: no behaviour change. test-check-vale-style-sync.sh and test-vale-wrap.sh
both pass (42 passed, 0 failed).
2026-08-17 10:09:51 +00:00
b93af30750 docs: fix a wrong pointer and two stale claims in CONTEXT.md
Why: CONTEXT.md is an instructed every-session read, so a wrong assertion in it
is cited downstream without being checked. The b9c7762 rewrite introduced one
broken pointer and carried over two claims that were already false.

Implementation notes:
- The Preload tax entry pointed at docs/spec/gates.md for the measurement
  method. gates.md has no such method — it uses the 23,427-char figure once, in
  passing, without deriving it. The method and the current figure both live in
  ADR-0020, which is where a dated measurement belongs: it is superseded there
  deliberately, and issue #99 tracks its drift.
- Dropped the "~5,900 tokens across 39 skills" measurement rather than
  re-measuring it. It was already wrong three days after being written (~5,340
  today) and it was the only live number in the file. Every sibling entry is one
  definitional sentence plus a pointer fragment; this one now matches, and
  CONTEXT-FORMAT.md:43 asks for exactly that.
- Dropped "Written by the session-handoff skill or directly by the human" from
  the LESSONS.md entry. No session-handoff skill exists — LESSONS.md:7 records
  it as planned work. Who writes a file is not its definition.

Impact: removes the only rot surface in the file and the only assertion in it
that names an artifact the repo does not have.

Refs: #99
2026-08-17 10:06:26 +00:00
b9c7762463 docs: trim CONTEXT.md to a glossary and demote VISION.md
Why: CONTEXT.md is an instructed every-session read at 33,799 bytes (~8,450
tokens), and CONTEXT.md:17 layered docs/VISION.md on top. After the AGENTS.md
trim, that left ~9,650 tokens of instructed reads sitting behind a file whose
own format contract — grill-with-docs/CONTEXT-FORMAT.md:43, "Keep definitions
tight. One sentence max." — it was not following. 22 glossary entries averaged
190 words; the top four were 55% of the file, and one ("Vale audit prefilter")
was 1,444 words of pre-commit forensics filed as a definition.

Implementation notes:
- CONTEXT.md rewritten to CONTEXT-FORMAT.md's prescribed template: ## Language
  (five clusters, 22 terms with _Avoid_ aliases), ## Relationships,
  ## Example dialogue, ## Flagged ambiguities. 33,799 -> 9,762 bytes.
- Vale prefilter forensics moved to docs/spec/gates.md under nine subsections:
  the two-copy style layout, vale-wrap.sh and the Vale 3.15.2
  text.frontmatter.description limitation, the --config argv defect (E100),
  glob scoping, the rule inventory, and 0-files-means-NOT-RUN.
- Instruction-file format and the bidirectional-reference principle moved to
  docs/spec/architecture.md, the latter flagged as aspirational: no instruction
  file carries a `when:` field, only 2 of 39 skills do, and the reference
  scanner script it names does not exist.
- Added a per-plugin scope table to architecture.md so "which plugin owns this
  skill" survives the trim, and corrected its claim that the content index
  lives in providers/claude-code/CLAUDE.md — that file is now two import lines
  and the index sits in core/AGENTS.md.
- "Repo and Gitea are the only source of truth" moved from CONTEXT.md's
  Principles into AGENTS.md session rules; it was operative guidance in a
  glossary. docs/VISION.md and LESSONS.md added to the on-demand list.
- The apm-consumed install entry (432 words) was deleted outright: all four
  consequences are already carried by README.md, ADR-0018, gates.md and
  AGENTS.md.
- ADR-0013, ADR-0015 and ADR-0017 each pointed at CONTEXT.md sections that
  moved; amended with dated supersession notes rather than left dangling.

Impact: the every-session set drops from ~15,700 to ~4,140 tokens across both
passes (-74%). The deleted "lint plugin" entry was also stale on a safety
claim — it said lint-runner inherits Edit, but ADR-0016 restored
`disallowedTools: Edit, Write, NotebookEdit` and CONTEXT.md was never updated.

Refs: #99
2026-08-17 09:28:01 +00:00
1929ffd2da docs: slim AGENTS.md to per-session context only
Why: AGENTS.md is preloaded into every session via CLAUDE.md's @AGENTS.md
import, so every word is a tax paid whether or not it is relevant. It had
grown to 3,371 words (~4,550 tokens), 75% of it a single "Setup and testing"
section that was mostly neither: roughly 1,600 words were gate forensics —
why a hook is shaped the way it is, what was tried and rejected, verification
numbers — and only ~390 words were genuine one-time setup.

Implementation notes: split three ways by audience rather than by heading.
One-time setup, prerequisites and test commands move to a new root README.md,
which did not previously exist. The gate forensics move to a new
docs/spec/gates.md, preserving every constant, hook ID, error string and
tried-and-rejected note (policy.fetch_failure_default, the removed fallback
frontmatter reader, extending skill-size-check's files: pattern to agents,
tidying .claude/settings.json out of the pretty-format-json exclude list) —
these exist to stop settled decisions being re-litigated, so none were
dropped. AGENTS.md keeps only what applies every session, at one clause of
rationale per rule. The .apm/-mirror section collapses to a pointer because
docs/spec/architecture.md already covers it in full. The hot ADR-0020 gate
counts stay in AGENTS.md deliberately: they block any skill edit today.

Also corrects docs/spec/architecture.md's stale claim of 19 ADRs; ADR-0020
landed without updating the count.

Impact: per-session preload drops from ~4,550 to ~1,116 tokens, a 75% cut.
agentsmd-audit passes: secrets clean, drift clean, 4 informational findings
for sections deliberately relocated to the README.
2026-08-17 08:56:37 +00:00
123ece2fb3 chore(apm): refresh lock after SessionStart auto-update
Why: kyberforge's SessionStart hook found six packages behind the holocron
default branch and ran `apm update --yes`, which re-resolved every unpinned
dependency ref and rewrote the lock. The dependencies are declared unpinned
against the default branch, so this churn is expected rather than a defect.

Impact: pins the deployed skill and agent set to the refs resolved this
session. No manifest or plugin content changed.
2026-08-17 08:56:22 +00:00
9385c77ac7 Merge pull request 'feat(kyberforge): ADR-0020 context contract for skills and agents' (#103) from refactor/trim-skills-agents-context into main
Reviewed-on: https://git.dev.rkdr.net/Defame1297/holocron/pulls/103
Reviewed-by: Defame1297 <gitea@rkdr.net>
v2.0.0
2026-08-16 21:20:02 +00:00
54d7bd80ba docs: rule host built-ins out of the routing target universe
Closes the second open design decision on PR #103. The `/compact` finding was
recorded as a false positive needing an allowlist or a suppression mechanism.
It is neither: the routing universe is the apm marketplace, so a target either
resolves to a skill or an agent or it does not resolve, and `/compact`,
`/clear` and `/init` are Claude Code slash commands with no counterpart in
Copilot CLI or Codex. `.apm/` source compiles for all three, so a
vendor-neutral description routing to one is a portability defect and the hard
FAIL is a true positive.

An allowlist was rejected for a concrete reason, not a stylistic one: it
answers a different question ("does this exist on some host?"), it cannot
answer that portably from a single source file, and it goes stale the next
time a host ships a command — reintroducing the same-commit-two-verdicts
failure ADR-0020 already closed for deployed trees.

Nothing is blocked today: zero of the 43 descriptions name a host built-in,
and an author who needs to mention one writes it un-slashed, which is not
route notation and carries no routing claim.

Recorded in ADR-0020 and in both author-facing contract references, so the
next agent reads the decision rather than "fixing" the gate.

ADR: 0020

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 20:45:19 +00:00
75a13c82f6 fix(kyberforge): scope corroboration to a real sentence boundary
A prose-form routing target blocks a commit only when its own sentence names
another target that resolves. That makes the sentence splitter part of the
ADR-0020 contract rather than an implementation detail, and the naive
"period, space, capital" rule got it wrong in both directions:

- OVER-SPLIT: `e.g. "..."` is not a sentence end, but the quote looks like a
  start. The clause was cut in half and the corroborator stranded on the far
  side, so a genuinely dangling target silently demoted to SUGGESTION — a
  measurement taken and then discarded, the vacuous-green shape this gate
  exists to prevent. Seven such splits are live in the current corpus.
- UNDER-SPLIT: a sentence opening with a code span or a lowercase skill name
  was not seen as a start, so two sentences merged and a resolving target
  vouched for an unresolvable one it never stood beside — a hard FAIL with no
  escape hatch, which is the exact failure corroboration was added to prevent.

The splitter now excludes the five abbreviations that occur in routing prose
and admits a backtick or lowercase letter as a sentence opener. Applied
byte-identically to all three copies of the shared resolver.

Verified zero-delta against the corpus: 37 ERROR / 58 SUGGESTION / 2 dangling
before and after, findings byte-identical. The exposure this closes is to the
descriptions #99 is about to rewrite, not to the ones already measured — which
is why the deferral reason recorded on PR #103 ("can move the documented corpus
counts") does not hold and the fix lands here rather than after the retrofit.

Three regression tests, one per direction plus the backtick opener, each proven
non-vacuous by reverting the splitter alone and watching it go red.

Refs: #99
ADR: 0020

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 20:44:58 +00:00
79c9089122 docs: make the resolution contract match what the gate actually does
Both AGENTS.md and ADR-0020 said deployed .claude/.agents trees are consulted "only
when no authoring root exists". That stopped being true in f7cc279: the walk-up
finds a root in any git repo, so the condition is now whether that root holds
plugins, not whether one was found at all. Left alone, the two documents describe a
resolver that no longer exists — and this repo's prose is load-bearing, since the
next agent reads it instead of the code.

Both now also record why a name-count delta is not an equivalent test, because it is
the obvious simplification and it is wrong: a single-plugin monorepo re-collects its
own package, adds no new name, and would pull the deployed trees back in.

ADR: 0020

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015W3iwF9ncfRZddGBxsMCYi
2026-08-16 19:49:50 +00:00
ede3f06689 fix(kyberforge): restore the authoring rules the ADR-0020 trim dropped
Diffing each retrofitted SKILL.md against its replacement references/ files found
rules that existed on main and now existed nowhere — relocated in intent, deleted in
fact. A trim that loses a rule is not progressive disclosure, it is data loss with a
smaller word count.

Three had no survivor. The least-privilege guidance for `tools` kept its mechanics
and lost the "restrict to what the agent needs" half, so the remaining text read as
encouragement to omit the field. The improve flow lost its regression check, so
nothing compared the closing audit against the pre-edit state and a PASS quietly
becoming a SUGGESTION went unnoticed — restored on both halves of the author pair,
since agent-author had dropped its equivalent too. And agent bodies lost "would the
agent get this wrong without it?", which mattered more than it looks: ADR-0020
deliberately sets no body word gate for agents, three of the four already sit
between 933 and 1,199 words, and the delegation check only fires on procedure a
skill already owns. That heuristic was the only brake left.

Two more were reachable only from the wrong scope. agent-author tells the reader to
load only the file for the resolved scope, but the mcp__ glob syntax for
disallowedTools and the five tools no subagent ever receives had both landed in
project-user-scope.md. disallowedTools is the ONLY permitted fence at plugin/APM
scope, so the scope that needs the syntax most could not reach it, and a plugin-scope
run could write a body telling the agent to ask the user a question.

Two documents were actively wrong rather than merely thin. agent-audit told auditors
that validate.sh resolves boundary targets for skills only; it runs at both scopes,
so the auditor was hand-resolving what the script had already decided and could
contradict it. And skill-audit routed to its script-troubleshooting reference
whenever validate.sh "fails" — but it exits 1 on ordinary content FAILs, the normal
outcome for the whole #99 population, so 1,302 words loaded on nearly every audit.
A context-budget regression inside the skill that enforces the context budget.

Finally, two illustrations taught the shape the gate ERRORs on, unfenced, while an
adjacent rubric called it a hard ERROR.

LESSONS.md records the reference-chain depth rule flipping from "one level deep" to
"two hops, never three". ADR-0020 is silent on it and the reversal rode entirely on
the diff; the looser rule is what mandatory dispatch requires.

Refs: #99
ADR: 0020

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015W3iwF9ncfRZddGBxsMCYi
2026-08-16 19:49:38 +00:00
b0d6d08239 test: pin the nine ADR-0020 gate defects that shipped untested
Every defect fixed in f7cc279 was reachable because nothing asserted against it.
The gate had 43 assertions and none of them covered a consumer repo, a non-string
description, an unclosed fence, or the two spec ceilings. Each case below fails
against the pre-fix code and passes against the current one; every one was proved
non-vacuous by mutating a scratch copy of the script and watching the test go red,
independently twice.

The two that mattered most had no fixture anywhere. A consumer repo WITH .git is
the shape the resolver exists to serve, and only the no-.git case had ever been
tested, which is exactly why the blocker was invisible. And ADR-0020 says the
walk-up runs in two passes specifically so a nested .git cannot beat a plugins/
root further up — no fixture had ever placed a .git inside a plugin.

test-adr0020-differential.sh loses _non_adr_hook_error(). It excluded MAX_LINES and
MAX_WORDS from the cross-script comparison on the untested assumption that awk and
splitlines() agree. They do not, and the divergence stayed invisible for exactly as
long as the exclusion stood. The ceilings are now compared like any other rule.

Two existing assertions were repairs, not additions. The skill-improve probe had
been fixed by this very branch, so its iteration permanently took an
assertion-free SKIP that still counted as a pass; both branches now fail loudly and
each names the other file's pin so the two stay in step. And the yaml-none fixture
emitted `---/---`, which never matched the frontmatter pattern at all — it passed on
the bare word "frontmatter", present in both messages, while never reaching the
branch it was named for. Needles throughout that file now name their branch.

Refs: #99
ADR: 0020

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015W3iwF9ncfRZddGBxsMCYi
2026-08-16 19:49:15 +00:00
f7cc27908c fix(kyberforge): close the vacuous-green and consumer-resolution defects
Review of the ADR-0020 gate found four ways it could exit 0 without measuring, and
one way it hard-failed a repo it had no business failing. On a gate shipping hot
with no baseline, a silent pass is the worst outcome available and a false block is
the second worst.

Consumer resolution was the blocker. _authoring_root() fell back to the nearest
.git, so it returned truthy in ANY git repo; _collect_authoring_root() then
contributed nothing and the deployed-tree branch was dead code in precisely the
consumer case it exists for. A consumer repo routing to an installed sibling got an
unblockable ERROR, and deleting .git "fixed" it. It now keys on which of the two
walk-up passes matched. A name-count delta was tried first and is wrong: a
single-plugin monorepo re-collects its own package and adds no new name, so the
delta reads zero and drags the deployed trees — including a global ~/.claude — back
into the universe. That reintroduces the install-dependence ADR-0020 forbids, one
layer down.

The three silent passes: an indented `---` inside a block scalar truncated the
frontmatter and reclassified the rest of the description as body; a non-string
description was str()-coerced, so `description: true` measured as the four-character
"True"; and an unterminated fence blanked the rest of the body, disabling the
ERROR-tier references/ check and the gotcha counts.

Two measurement defects came with them. The awk line/word counts discarded awk's
exit status, so an unreadable file passed both spec ceilings in total silence, and
awk NR/NF disagreed with the audit script's splitlines()/split() on Unicode
whitespace — the "fix one gate, get blocked by the other" bug, on the two axes the
differential test deliberately excluded. Both counts now run in the Python block
that already reads the file. A type error also no longer reports itself as a syntax
error.

Also: glob metacharacters in the checkout path silently disabled the resolver;
re.I was applied to some extraction patterns and not others; agent-audit missed
`tools:` written as a YAML block sequence, the shape Copilot files use; and a
nonexistent agent file raised a bare FileNotFoundError instead of a diagnostic.

The shared resolver block stays byte-identical across all three scripts. Corpus
output is unchanged — 26 description FAIL, 9 body FAIL, 2 dangling, 0 missing
references, 58 SUGGESTIONs — so no documented count moves.

Refs: #99
ADR: 0020

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015W3iwF9ncfRZddGBxsMCYi
2026-08-16 19:48:56 +00:00