Repository navigation
0.5.0
-
The PHP tooling tree's three propose-time stop conditions are now recognition-only gate nodes in the
shipped tree (skills/refactor-scan/references/php-tooling-tree.md), modeled onis-php-project:
has-real-dependency(the project has a real, non-platform dependency) gatescomposer-audit,
phpstan-baseline-empty(the current PHPStan baseline is empty) gates every PHPStan level above zero,
andphpstan-not-psalm(PHPStan, not Psalm, is the project's analyzer) gates the first level above
zero. Each is never proposed — only a required parent carrying a Purpose and an agent-judged
Fulfilment check in its tree doc — and the graph logic carries no special-case flag for these
situations any more; what gets proposed on any target is unchanged. -
continuous-refactoringis now a thin dispatcher: it only selects a Track (references/track-scheduler.md,
unchanged) and invokes that Track's own skill. The pass itself (scan → prioritise → design → implement →
learn) moved into a new track-agnosticrefactor-loopskill that requires a Track and aborts without one;
continuous-safety-net,continuous-guardrailsandcontinuous-investigationdelegate to it, and
continuous-housekeepingowns Housekeeping's own process with its three reference files. Only
continuous-refactoringis a user entry point (/continuous-refactoring, with or without a Track name,
behaves as before); the new skills are internal. See ADR-0057. -
Safety Net Track:
refactor-scannow judges a Safety Net Track node's Fulfilment check against its
own Purpose statement (an agent walking the tree), instead of trustingtooling_tree.py's raw
dependency-name match alone — a target already running Laravel Pint is recognized as fulfilling
php-cs-fixer's Purpose and is never proposed a redundant, possibly colliding second style tool.
bookkeeping.mdgains a## Safety Netsection (Cadence,Last scan,Open,Out-of-scope),
replacing the oldFulfilled nodes/globalPending candidatesfields for this Track's own nodes;
refactor-learnwrites into it symmetrically — merge removes an entry fromOpen, rejection removes
it and writes bothout-of-scope/<slug>.mdand anOut-of-scopepointer. A repo on the old
bookkeeping.mdshape runs a normal pass, unaffected. -
Guardrails Track:
refactor-scannow judges a Guardrails Track node's Fulfilment check against its
own Purpose statement, the same mechanism ticket 01 established for the Safety Net, applied to the
seven nodes required onstructural-scan/php-safety-netthemselves (composer-audit,phpmd,
coverage-floor,php-minimal-version,phpstan-level-6and above,phpstan-deprecation-rules,
semgrep) — proposed only once the Safety Net has closed.bookkeeping.mdgains a## Guardrails
section (Cadence: 60,Last scan,Open,Out-of-scope), independent of## Safety Net;
refactor-learnwrites into it with the identical merge/rejection symmetry
safety-net-write.mdalready established. A repo mid-migration —## Safety Netalready closed,## Guardrailsnever run — runs a normal pass, unaffected. -
Dev-repo CI:
tier3(Ground Truth) and theroadmapfixture matrix no longer gatetest-harness.yml.
Both asserted againsttooling_tree.py's own deterministic, hardcoded-dependency-name matching for
Safety Net/Guardrails nodes — which tickets 01/02 (ADR-0055) made no longer the operative fulfilment
path for those nodes — and CI has no model credentials to run the agent-judged check that replaced it.
Both remain runnable locally viafixtures/harness/run.sh's existing--opencodeflag, the same
local-only/advisory posturetier4's non-deterministic parts,judge,lift,agent-loop, and
decision-gate-bypassalready use.tier1/tier2are unaffected and still gate CI. -
Track scheduler: the orchestrator now runs real competition between every currently-wired Track
(Safety Net, Guardrails) instead of each Track deciding on its own whether it's due — a new
Track-selection step (skills/continuous-refactoring/SKILL.mdstep 0b,
skills/continuous-refactoring/references/track-scheduler.md) computes each due,Open-empty Track's
overdue_ratio = (today − Last scan) / Cadenceand hands the highest-ratio one torefactor-scanas
an explicit input; a tie (or two Tracks that have never run) falls back to the fixed order Safety NetGuardrails > Housekeeping > Investigation. A Track with non-empty
Openstill always has its
existing work worked instead of being rescanned, and a human can still name a Track directly to bypass
selection entirely. Written generically over every Track carrying a bookkeeping section, so
Housekeeping and Investigation slot into the same mechanism later without another rework. The
suite-wide open-MR cap (refactor-prioritizestep 1) was already Track-agnostic and needed no change. -
Investigation now has its own
bookkeeping.mdsection (## Investigation,Cadence/Last scan
only — noOpen/Out-of-scope, a structural candidate's own state still lives on the issue tracker /
merge-requests.mdas before) and joins the Track scheduler's real competition
(skills/continuous-refactoring/references/track-scheduler.md). ItsCadenceis always the literal
continuous— no fixed interval, always due, always eligible — which makes it the scheduler's
permanent fallback: it only wins a pass the moment no other wired Track (Safety Net, Guardrails) is
both due and eligible, consistent with the fixed tie-break order Safety Net > Guardrails > HousekeepingInvestigation.
structural-scan's own candidate-search behavior is unchanged — only when it gets
proposed changes: gated behind Investigation Track selection (skills/refactor-scan/references/ investigation-track.md) instead of proposed unconditionally every pass. -
The standalone
continuous-housekeepingskill is retired. Its process — due-check, reconciliation
against fulfilled nodes, checklist assembly fromhousekeeping-template.md, quality gate, deliver —
is unchanged, but now runs as the Housekeeping Track's own content
(skills/continuous-refactoring/references/housekeeping-track.md), triggered by the shared Track
scheduler (skills/continuous-refactoring/references/track-scheduler.md) instead of its own standalone
due-check.bookkeeping.mdgains a## Housekeepingsection (Cadence,Last scanonly — no
Open/Out-of-scope; swept content stays inhousekeeping-template.md, unchanged) — a hybrid of
Investigation's shape and Safety Net's/Guardrails' own:Cadencedefaults to7(days, unchanged from
today's default) and is hand-editable, unlike Investigation's permanentcontinuous, but there's no
in-flightOpenlist, unlike Safety Net/Guardrails. Manual invocation of the Housekeeping Track
directly stays possible, generalized to the same Track-name-as-argument pattern Safety Net, Guardrails,
and Investigation already use — one shared invocation surface across all four Tracks now, replacing the
old skill's own separate/continuous-housekeepingentry point. No standalonecontinuous-housekeeping
skill remains; itsreferences/(cadence interview,housekeeping-template.md's own format doc) moved
undercontinuous-refactoring. -
The Track scheduler gains a one-time exception, checked first, before any
overdue_ratio/tie-break
computation: the pass right after Safety Net's ownOpenfirst empties runs Investigation once
(one candidate, fully delivered), then the following pass runs Guardrails once (its own first
scan-and-clear cycle), then the pass after that runs Housekeeping once (its own first cycle) —
each overriding ordinary selection for exactly that one turn, so a target sees one real piece of
delivered refactoring value before being asked to adopt more tooling or sit through maintenance.
Ordinary staleness-ratio scheduling resumes permanently once Housekeeping's turn completes — including
Safety Net's own later, rarer rescans. Tracked entirely from the existing Track sections'
Last scan/Open/Pending candidatesstate — no new stored flag: each of Investigation's/Guardrails'/
Housekeeping's own "have I ever run" section-presence, plus (for Investigation only, which carries no
Openof its own) whetherPending candidatesstill names its in-flight candidate, is what makes the
exception fire exactly once per repo (skills/continuous-refactoring/references/track-scheduler.md's
own "One-time exception" section). -
A selected node-based Track is now worked one
Opennode per pass, top to bottom
(skills/refactor-scan/references/track-open-processing.md): the topmost workable node is picked up,
its Fulfilment check is re-run right before its issue is created — a node fulfilled by hand since the
scan leavesOpenwith no merge request and the pass moves on — and non-workable nodes are collected
with a reason for the pass report. Track nodes are no longer pre-filed as issues at proposal time
(amending ADR-0047's pre-filing decision for them): the issue is created only when the node is
actually worked, and Rank mode no longer chooses among Track nodes. Three new advisory agent fixtures
cover the pick-up re-check (php-track-open-hand-adopted), the top-to-bottom order with a blocked
node in between (php-track-open-blocked-in-between), and a priority-labeled issue waiting behind the
top ofOpen(php-track-open-priority-vs-top). -
The Track scheduler implements Safety Net blockade, Guardrails yield, and Housekeeping preemption
(skills/continuous-refactoring/references/track-scheduler.md). While Safety NetOpenis non-empty,
Safety Net is selected and nothing else runs — even if no node is currently workable; what it waits on
is reported. Guardrails with a workableOpennode is selected ahead of Investigation; Guardrails with
Opennon-empty but nothing workable yields, itsOpenstays as it is, and the pass report lists
every stalled node with its reason. Housekeeping preempts Guardrails for one pass when due
(overdue_ratio >= 1), then Guardrails resumes afterwards. The one-time bootstrap exception advances
past Guardrails' non-emptyOpen— it reads only whether each section exists, not whether itsOpen
is empty. Four new advisory agent fixtures exercise these rules:php-scheduler-safety-net-blockade,
php-scheduler-guardrails-stalled,php-scheduler-housekeeping-preempts-guardrails,
php-scheduler-bootstrap-guardrails-open. -
The Housekeeping Track's reconciliation now sweeps via agent judgement
(skills/continuous-refactoring/references/housekeeping-track.md): each cycle it checks only the
nodes that carry aHousekeepingfield, judges each one's Fulfilment check against its Purpose, and
appends any missing checklist line — so a tool adopted by hand, Guardrails tools included, gets its
line even when no delivering merge request ever existed. TheFulfilled nodesbookkeeping field is
retired: no skill reads or writes it any more, and abookkeeping.mdthat still carries the old field
is left untouched and ignored. Covered by two new advisory agent fixtures:
php-housekeeping-hand-adopted-guardrailsandphp-housekeeping-old-schema. -
skills/refactor-scan/references/tooling_tree.pyno longer detects anything: the hardcoded
dependency-name detection and the forward-simulatingroadmapoutput are deleted, and the script now
takes a fulfilment seed (--seed, or the Refactoring Notes'fulfilled-set.json) or derives state
frombookkeeping.md's Track sections, computing the tree's graph logic only — the orderedOpen
backlog, workable and withheld nodes with reasons, rejection cascades, PHP-floor findings, and the
merge-request outlook (--unblocked-by). The harness'sroadmaptier and the eight
expected/roadmap.jsonfixtures are removed with it; the drift check comparing the manual tree-walk
fallback with the script's graph logic continues asscripts/drift_check.py, advisory and run
manually (never collected by CI'stest_*.pydiscovery). -
Safety Net and Guardrails Track
Openentries now record their issue number (- <slug> (#<issue>)) as soon asrefactor-designfiles it, instead of staying unlinked until a merge request opens or merges — closes a bookkeeping gap that previously forcedrefactor-scanto rediscover already-filed tickets by searching instead of reading the link. -
Cross-skill citations inside
skills/**(one skill'sSKILL.md/reference file pointing at another skill's reference doc) are now written relative to the citing file instead of the suite repo's root — the old form never resolved once a skill shipped into a target repo, forcing an agent to search the filesystem for a file it was told to consult.scripts/validate_skills.pynow checks the new form and flags any reappearance of the old one.safety-net-track.md/guardrails-track.mdno longer imply a node's tree-doc file can be derived from its slug alone (php-tooling-tree/<node>.md) — a multi-node file likerector.md/psalm.mdbroke that assumption and sent an agent searching for a file that doesn't exist under that name. Both now point atphp-tooling-tree.md's own per-node Full definition pointer instead, which always names the right file. -
php-structural-scanrenamedphp-safety-net.CONTEXT.mdgains Onboarding (the bounded
phase beforestructural-scanopens) and its narrower Safety Net, plus a new Signal wave:
composer-audit/phpstan-deprecation-rulesmove out of the PHP Safety Net into the Signal wave
(gated onphp-safety-netclosing, in addition to their existing required parent, so a rejected
parent still permanently closes them);phpmd/coverage-floor/php-minimal-version/
phpstan-level-6join the Signal wave the same additive way;semgrepis fully repointed onto
php-safety-netalone (its oldcomposerrequired parent dropped); the generic root's
secret-detectionnow waits forstructural-scanitself to open instead of proposing from the
very first pass.composer-audit/semgrepalso gain a Housekeeping-line fulfilment fallback (a
committedhousekeeping-template.mdline naming the node, no CI run required). -
phpstan-level-0detection now falls back tophpstan.neon.distwhenphpstan.neonis absent
(PHPStan's own auto-discovery order, already honored elsewhere in this tree for
phpunit.xml.dist/psalm.xml.dist/phpmd.xml.dist).phpstan.neonstill wins when both files
exist. Fixes a false "no level configured" report on targets that only ever committed the.dist
file. -
A Track's
Cadencecan now be written with a unit —12 hours,7 days,2 weeks,1 month— or as a fixed monthly day (monthly on the 1st); a bare number from an olderbookkeeping.mdstill reads as days, and the loop now writes its defaults as90 days,60 daysand7 days. -
Docs refresh: README now explains the four Tracks (Safety Net, Guardrails, Housekeeping, Investigation), the dispatcher/
refactor-loopsplit and the two-merge-request cap, and indexes all docs. Newdocs/playbooks/tracks.md(how Tracks are selected, the one-time exception, working open items, overrides) anddocs/architecture.md(skill hierarchy, one pass step by step, subagent hand-back, tooling tree, loop state). The loop and Housekeeping playbooks, FAQ and known-limitations (now with a "why did the pass end without doing anything?" troubleshooting table) are brought in line with the current skills. -
The loop now says what it is doing while it runs: one sentence before and after each step (scan, ranking, design, implementation, recording), and a separate line for every change it makes in your repository — an issue created, a branch pushed, a merge request opened. Housekeeping reports the same way.
-
Onboarding is now its own first step of
/continuous-refactoring: on a project with nobookkeeping.mdthe very first output says onboarding is starting, a short interview (tracker, merge-request mode, where the Refactoring Notes live — plus a one-time "stop and set up the engineering skills, or continue?" question when their issue-tracker and triage-label files are missing) runs inline, the setup files are written (bookkeeping.mdlast) and the invocation ends with a closing text: commit the files, then run/continuous-refactoringagain to start the first scan. No scan subagent, issue, merge request, branch or forge action is involved, and no label is created on GitHub/GitLab (the closing text listsgh label createcommands for GitHub).continuous-safety-net,continuous-guardrails,continuous-investigationandcontinuous-housekeepingnow abort with a pointer to/continuous-refactoringon a project that was never onboarded. The tooling-tree nodeloop-config("Refactoring Config") is renamedonboarding-setup("Onboarding Setup"); targets with an old-styleloop-configcandidate already open are not migrated. -
The
bookkeeping.mdthe onboarding writes is now titled# Refactoring Bookkeeping(was# Refactoring Loop Config); existing files keep working unchanged. On an already-onboarded project a pass no longer says anything about onboarding. -
refactor-scan's tooling-tree step now appliesphp-tooling-tree/psr-4.md's own judgement call
before treating a non-emptyunwired_entry_pointsresult as real unaddressed work: files that never
reference the target's own PSR-4 root namespace and are self-evidently dev/CI/build utilities are
exempt. Fixes a false "PSR-4 autoloader not wired" report on targets (e.g. Laravel-style repos) whose
entry-point sweep also picks up framework config/migration files that were never meant to require
the autoloader themselves. -
The retired
Fulfilled nodesbookkeeping field is removed from the documented schema and from every fixture and harness check. Nothing changes for abookkeeping.mdthat still carries it: the block is ignored, and can be deleted by hand at any time. -
New
Ticket-create-modesetting (autonomous, orask-each-timeto be asked before a ticket is created), asked in the onboarding interview right after the tracker. Only the loop creates tickets now — the steps that propose candidates hand it drafts — and withask-each-timeit asks once for the batch of proposed tickets and once for the candidate it chose; a refused or unanswered ticket ends the pass without writing anything. A missing field meansautonomous, so existing targets behave as before. -
Create-modeis renamedMR-create-mode(values unchanged) — it only ever governed how merge requests get opened. An olderbookkeeping.mdwith the old name is still read, and renamed on its next bookkeeping write.