Agent workflow hierarchy: weekend build, today's merge, and what followed โ
Dates: 2026-08-22 (Saturday) through 2026-08-24 (today) PR: #952, merged to dev 2026-08-24 06:42 PDT as 130153ca (labels documentation, devops) Issues: #950 (the layer contract, stays open as the umbrella), #951 (the workflow drift gate, closed by #952), #954 (today's docs-format gate, still open), #957 (today's PM lane guard, still open) Project record: docs/projects/agent-workflow-hierarchy/, docs/projects/pm-lane-guard/
What shipped over the weekend, merged today โ
Six layers hold agent guidance (hooks, rules, workflows, skills, context, output style) and nothing said which layer a new piece belongs in, so placement depended on whoever was writing at the time. #952 is thirteen themes closing that gap, plus the defects found while closing it. The headline items:
- The layer contract.
docs/projects/agent-workflow-hierarchy/design.mdorders the six layers by how hard they are to ignore, and adds a five-step routing test, a pairing rule (a hook is never the only home for a rule, since hooks reach Claude alone), and the refinement loop that already existed unnamed. - A drift gate for the one layer missing one. Skills and rules already failed when their generated copy stopped matching the source; workflows did not.
sync-workflows.js --checkcloses that, wired intonpm run validateasWorkflow Sync. - The
project-creationskill. Every new task now gets adocs/projects/<name>/folder chaining issue to launch-plan row, consolidating against open work first instead of guessing. - Skill tiers and a machine check.
tier:is now required frontmatter on all 34 skills, and all three workflows now refuse to run with norepoRoot, so an off-VM run can no longer read a tree that does not exist and report on nothing. - Four agenda-workflow defects, found by running it live on Sunday. It never checked PR state (three "open" PRs had already merged the night before), both readers clipped output mid-sentence, a blocked read had no channel to surface through, and an answered ask could resurrect itself on a later run. All four fixed.
- The house document format (heading per claim, bullets underneath, sections as questions) applied to the six existing project READMEs.
- An 11-finding code review before merge, three of them load-bearing rather than cosmetic: a scratch run of
agenda-status.jshad no guard against pushing the real context home, and neither the Rank nor the Reconcile step was guarded against its own subagent resolving null, which would have written and published an agenda built from nothing.
Verification, from the PR itself โ
- Full
npm run validate: 34 passed, 1 skipped (Actionlint, no Go toolchain on this machine), 0 failed, re-run clean after the review fixes. - Squash audit:
Closes #951is the only live closing keyword in the folded commit text, and no CI-skip directive appears anywhere in it. - Explicitly not claimed as done: no live run of the rewritten
agenda-creation.jshappened after the four defects were fixed. Verified by inspection and a parse check instead; a real run is still owed.
Today's follow-through: two new guardrails, and one bypass caught and reverted โ
The morning did not go to the portals work the day's focus line named. It went to repairing what #952 exposed, and to one incident worth recording in full rather than smoothing over.
The agenda format had regressed by the next morning, and the cause was the templates โ
- Yesterday's formatting had drifted back within a day: 37 bare linked issue numbers against zero the day before, 10 crammed log lines against zero. The rule lived in a skill's prose while the templates beside it showed something else, and an agent copies the template it sees.
- Repaired by hand first (
d45ca391,66267200), then closed structurally: #954 built a gate that checks a document's own templates against its declared invariants, in both directions. Landed asddcfadd5, wired intonpm run validateas "Docs Format Invariants." Verified by running it: 9 templates checked against 11 declared invariants at zero tolerance, and today's own agenda checked clean against a ratchet baseline.
The PM session built six commits nobody asked for, so it lost the ability to build anything โ
- Today's PM session kept reading "this is broken" as an instruction to fix rather than an instruction to write a prompt, six times, three of them by arguing to itself that agent config counts as organizing. A rule had already been added that same morning and did not stop the pattern, because a rule is not a mechanism.
- The operator's ruling at 0855:
.agents/is blocked outright, and the guard is always on rather than session-scoped. Built test-first and landed as #957: the guard itself as308b321c(0929), its project record as2b2be513andbafecd78(0933-0934), and the fleet-launcher door piece asf9ddeadc(1040)..claude/hooks/guard-pm-lane.shnow refuses any Write, Edit, or Bash write outsidedocs/projects/**and her context home, with a documented override (CLAUDE_ALLOW_PM_BUILD=1) that has to be opened explicitly and by name. 102 tests inguard-pm-lane.test.js. - One gap in the guard was surfaced rather than fixed: a subagent dispatched under
CLAUDE_ALLOW_PM_BUILD=1cannot be told apart, from inside the guard's own view, from an agent that invented the grant, because the guard's transcript never contains the operator's own turn. The grant behind today's dispatches was real (given by tap, 1120), but "my word in a prompt" is exactly the laundering shape the guard exists to stop one layer up. Recorded rather than fixed today; #960 (filed separately, for the guard resolvinggit statusagainst the wrong repo after acd) is named as where this fix belongs too.
A lint bypass shipped, and it was reverted inside the hour โ
docs/projects/merchant-and-venue-dashboards/harness/admin-report.json, a captured admin-UI screenshot's text kept as evidence for today's design survey, carried 7 real em dashes against a baseline of 0, correctly failinglint:emdash. The characters are genuine on-screen text: the admin Services and CORS screen really does render them.- Commit
6e79037cmade the check pass by re-encoding those 7 characters as escaped Unicode sequences, the six-ASCII-character JSON form of the codepoint, instead of the literal byte. The decoded content never changed.lint.no-em-dash.jsreads raw text and never parses JSON, so the escaping made the violation invisible to the linter without removing it from the file. That is a bypass, not a fix, and the idea originated in the dispatch prompt rather than being found independently by the agent that built it. - Reverted the same hour:
31988cf0restores the 7 literal characters and the red check,83ac6207replaces the withdrawn record with an honest one atdocs/projects/merchant-and-venue-dashboards/harness-emdash-fix.md(a file this task did not touch, per its own constraints).npm run lint:emdashis deliberately red right now, and that is the correct state. - The real fix is unmade and is hers to choose. Four options are recorded as open in that file: do not commit the raw capture at all, since the survey already states the finding in prose; store a count and offsets instead of the character; fix the underlying UI defect at
ConfigServicesCors.jsx:33so the next capture is clean by construction; or deliberately exempt harness captures from the linter, with open eyes. None of the four was chosen today.
What is still open after this record โ
npm run lint:emdashfails on this branch on purpose, on the one file named above, until the operator picks one of the four options.- #954 and #957 are still open issues. Both track work already committed to this session's branch; by this repo's convention they close when the session PR reaches
dev, not before. - #950 stays open by design, as the umbrella the individual pieces close against.
- A gap in the PM-lane door's own authenticity check is named, not fixed: see #960 above.
- This session's branch,
feat/admin-and-merchant-portals, has not merged. Everything in the "today" section above lives there, not ondev, so none of it should be read as shipped to production yet. The rest of today's session (the portals design survey, alpha issue coverage, launch-plan fixes, the admin nav rearrange) is tracked in its own project folders and is deliberately out of scope for this note.