Repository navigation
Releases: Art4/continuous-refactoring
Release list
0.10.0
- Semgrep and Psalm's taint analysis are no longer proposed to every project: they are now set up only when you ask for them, by naming one in the call ("set up Semgrep") or by asking for a scan including the tools on request, and each scan report names what is available. Composer Audit is no longer a tool to set up: the first Housekeeping template now carries a recurring dependency audit for any package manager, an existing template gains it on its next cycle, and an open "Composer Audit" or "PHP Version Floor" ticket is offered for closing with a note saying what took its place. The diagrams under docs/tooling now show a tool's status as the outline of its steps — dashed for on request, dotted for recognized — with a legend below.
- Secret Detection is now set up only on request, and the secret scan over the Git history no longer waits for it: Housekeeping uses your project's own secret scanner, or runs one of its own (gitleaks, for instance) without adding anything to your project. A forge's push protection for secrets now counts as Secret Detection being in place, and the scanner's findings no longer feed the Security signal of restructuring candidates.
- Mutation testing joins the tooling, on request: ask for Infection and the suite sets it up after your coverage floor, with a minimum score that only rises, a pipeline check on the changed files and a full run in each Housekeeping cycle; the faults your tests miss then point the search for restructurings at code that is run but not really tested. A project that already runs Pest's own mutation testing has it in place. A tool on request that needs a newer PHP than your project allows is no longer reported as out of reach until you ask for it.
- The suite now asks whether your project promises stability to code outside it — your package's users, your application's addons — and records where that promise is written (or that there is none) in
docs/agents/issue-tracker.md. Onboarding asks it; a project onboarded before is asked once at the start of its next run. Code the promise covers is restructured with old and new side by side and the old path deprecated the way your promise says; its removal is proposed as an ordinary ticket, never made by a refactoring. - A project whose BC promise follows SemVer and that has tagged a release now gets Roave's Backward Compatibility Check in its Safety Net, run in CI from its Docker image, before the suite's restructurings start. Rector's type coverage waits for it, and where your promise covers extending non-final classes it takes the BC-safe
art4/rector-bc-libraryset instead of Rector's own, so an added type does not break a subclass in someone else's code. - After the coverage floor, the suite now proposes two more steps for PHP projects: every test says which class it covers, and then — on PHPUnit 10 or newer, not on Pest — also what it only uses, so coverage counts only what a test means to test and a class without a test of its own shows up as untested. Integration and functional tests are marked as medium and large tests and need no list of what they use. The merge request writes the tests a class lacks; where that does not fit, it sets the coverage floor once to the newly measured value and says so. A Pack of your own whose Tool gains a second Stage is now told to rename the Tool, not the Stage, so tickets and rejections on record keep their name.
- Rector's PHP set now goes up to the PHP version your
composer.jsondeclares and never above it, and the "PHP Version Floor" step is gone: the suite no longer raises your declared minimum PHP after rewriting the code for a newer one. A rejection of that step you recorded earlier is ignored. - PHPStan Level 4 now waits until Rector Dead Code is decided, and Level 5 until Rector Type Coverage is, so the rewrites shrink those levels' baselines before they are fixed by hand; Rector's PHPUnit Set is now a Guardrails Stage and no longer holds the Safety Net back.
- A Stage's
afterfield in a Pack is now namedwaits_for("B waits for A"), and the generated tooling tables call the column "Waits for". A Pack of your own that still saysafteris refused with a message asking you to rename the key. - A structural change that creates a new class or other type reachable from outside now gives it a test of its own, written first, instead of relying on the old code's test staying green; and before opening a merge request a run now executes every gate your CI applies to the whole project, such as a coverage floor, in full, naming any it cannot run locally.
- A run whose call names a ticket now looks at that ticket alone: it no longer searches every open ticket first, and reconcile checks only that ticket's merge request, so it writes nothing to tickets you did not name.
- An open question on a ticket now ends at the first comment that is neither the suite's plan nor another of its questions, whichever account wrote it, and an answer that declines the ticket is recorded as a rejection.
- A proposed tool whose judgement stays open is now filed with its question as an open question on the new ticket, so an autonomous run no longer leaves it unfiled and raises it again on every scan.
- An agent may now start
continuous-refactoringby itself, as it already couldcontinuous-housekeeping— for example one that hands each run to a subagent and reviews its merge request before calling the next. - A new Driver playbook describes an agent that calls runs one after another, each in a subagent of its own, reviews and merges each merge request in between, and asks you only where a decision is yours — with a prompt to copy into your project.
- Known limitations now name two effects of letting an agent drive runs: its comments on a waiting ticket count as your answer, and a run inside a subagent does every step in its own context.
docs/adr/README.mdlists every decision with its status — in force, amended, superseded in part or superseded — generated from the ADRs' banners, which the validator now keeps consistent on both sides of every relation.
0.9.0
- The tooling tree is now Roles, Tools and Stages delivered in Packs: a project on Psalm is no longer offered PHPStan, a project that is not PHP can have a fulfilled Safety Net from the language-neutral tools, a rejection can name a whole tool or role, and a tool the suite learns about later is picked up on the next run.
- The tools the suite knows are now drawn for humans:
docs/tooling/lists the Roles and, per Pack, the Tools and Stages with a diagram of what requires what. The pages are generated from the Packs, and the validator now fails on a Pack that breaks its schema, is not in the fixed form, has two recommended tools for one Role, names a missing details file, or whose page is out of date. - The prose for a tool now sits beside its Pack: the generic Pack's tools, the suite's two prerequisites and the smaller PHP tools moved to
packs/<pack>/<tool>.md, without the history of how they used to be wired. The PHP Pack also knows Laravel Pint and Easy Coding Standard now: a project on either has its code style settled, and PHP CS Fixer is not proposed to it. - The last tool files (PHPStan, Psalm, Rector) moved into the PHP Pack and lost the description of how the tools used to be wired; the two tooling-tree documents are gone. Every tool now has one file beside its Pack, and the Pack pages under
docs/tooling/link to it. - A project can keep a Pack of its own for tools the suite does not know: a
pack.jsonand a file per tool, named in a new optional Tooling Pack operation of its tracker file. Its steps are proposed like the suite's own; it can add tools, steps and roles, never redefine the suite's, and a clash ends the run's tooling step with an error that names both places. A Pack now names a scope (PHP, Twig, …): tools take each other's place only within a scope, so a code-style tool for Twig no longer competes with one for PHP. See the new playbook on adding a tool of your own. - A new Pack for Twig in PHP projects: it applies when the PHP project requires
twig/twig(the file extension of the templates does not decide) and brings Twig-CS-Fixer for the Code Style of the templates and TwigStan for their Static Analysis. Both stand beside the PHP Tools and do not take their place. - PHP_CodeSniffer is now a recognized Tool for the Role Code Style: a target that runs
phpcs/phpcbfhas the Role filled, so PHP CS Fixer is no longer proposed on top of it. - The PHP Pack Stage "PHP Minimum Version" is now called "PHP Version Floor", matching its Role Runtime Floor and the terms Floor correction and Floor raise; its slug
php-minimal-versionis unchanged. - Psalm Taint Analysis is now a Guardrails Stage instead of a Safety Net one: its findings can need a restructuring to fix, and that restructuring waits for the Safety Net, so the Stage no longer holds the Safety Net back and no longer has to be skipped to pass it.
- Twig-CS-Fixer is now a Guardrails Stage instead of a Safety Net one: a style pass over Twig templates no longer holds the Safety Net, and with it every PHP Guardrails Stage, back. TwigStan still waits for it.
- In the PHP Pack diagram, the Static Analysis Role now sits inside the Safety Net group instead of outside it.
- PHP CS Fixer now comes in two Stages, so a project with thousands of files gets its code style in merge requests a person can review. The adoption (
php-cs-fixer-adoption, renamed fromphp-cs-fixer) pins a PER Coding Style version, proposes a list of extra rules you may decline, checks the project's lowest PHP version, and takes in as many rules as one merge request can carry; it alone releases Rector. The new Guardrails Stagephp-cs-fixer-rollouttakes in the rules leftNot yet:one at a time, path by path, through a second config file, as the ticket "PHP CS Fixer: take in the remaining rules". A Housekeeping line looks for a newer PER Coding Style version. - PHPMD no longer starts with a baseline: the limits of its metric rules are set to the worst value the code has today, with a comment, and fall whenever a refactoring removes that worst value. Deliberate exceptions are suppressed at the code with a reason, the five rule sets (now with
design) are the default, and a project that already has a PHPMD baseline gets one merge request that replaces it. - PHPMD now comes in two Stages, like PHP CS Fixer. The adoption (
phpmd-adoption, renamed fromphpmd) installs the tool, sets the limits, takes in the rules one merge request can carry and adds the CI job; rules leftNot yet:no longer keep it unfulfilled. The new Guardrails Stagephpmd-rollouttakes in those rules one at a time, as the ticket "PHPMD: take in the remaining rules". A rule too large for one merge request is taken in directory by directory through a second ruleset,phpmd.rollout.xml, which CI runs over the directories already done, so they cannot slip back before the rule is in everywhere. - A Stage's
aftermay now name a Role as well as a Stage. The Rector Stages wait for the Role Code Style instead of PHP CS Fixer's adoption, so the tooling diagram shows PHP CS Fixer, Laravel Pint, Easy Coding Standard and PHP_CodeSniffer feeding one Code Style node that Rector waits on. When Rector is released does not change: a Role counts as decided once it is filled, or once every Tool that could fill it is decided. A target's own Pack can use the same form. - The suite no longer names one agent's question tool: it asks for the environment's multiple-choice question tool (Claude Code, Cursor and OpenCode each have one under a different name) and falls back to numbered options in chat when there is none, so questions are shown in Cursor and OpenCode too. A tool reply that no human gave counts as unanswered.
- A new optional operation, Ready after plan, lets a target mark a ticket ready for implementation (for example a label or a board column) right after the suite posts a plan on it. Without the bullet nothing changes.
0.8.0
- A structural refactoring ticket now starts with a Pinning Test — a test that holds today's behaviour and passes before any restructuring — which the plan names, the review checks, and the merge request reports; where none can be written at a reasonable cost, the run asks instead of restructuring unchecked.
- For a restructuring that reaches over several steps behind one edge, the plan can pin the behaviour with a script that runs the old and the new code on the project's own sample inputs and compares the outputs; the merge request says on how many inputs they agreed.
- A structural refactoring now has to make the code easier to follow: the review takes off any change that lowers the reader's effort nowhere, and the run ends without a merge request when none is left. Judgement aids — reader load, the Strangler Fig, the technique vocabulary — now live in their own principles reference, apart from the few binding rules.
- Plans now tell apart an API someone outside depends on (replaced piece by piece, old and new side by side) from an internal one (all callers moved and the old API deleted in one step), remove dead code before reshaping, and every rename is searched for across strings, docs and configuration.
- When a restructuring renames, moves or deletes something that can be referred to from outside the tested interface, the merge request now states the one fact the change is safe because of and how far it was proved — or that it is not proved.
- A plan for a tooling ticket now estimates how big its merge request would be and, where a person could not review it, is cut into parts at a seam of kind or risk, each worth merging alone.
- The suite's own review now sorts its findings into fix, note and dismiss: what the plan cannot fix is named in the merge request, a dismissal carries its reason in the closing report, and a finding against the plan is never dismissed.
- When a run works a ticket that already has a merge request, it now sorts the review comments instead of fixing all of them: a bot's comment is checked and then fixed, dismissed with a reason, or asked about (security, data and permissions are always asked); a person's comment is fixed or answered, never dismissed; each handled comment gets a short reply, and threads are left for the reviewer to resolve.
- A run now stops when the same failing check or review finding survives two fix attempts: the branch stays local, the ticket gets an open question in plain words, and no check is deleted, loosened or ignored to get green.
- The design now settles a question about behaviour, output or timing by running something harmless instead of asking you, and a run's closing report opens with how many things wait for you and says what is recommended and what happens if you do not answer.
- A PHPStan baseline ticket's merge request may now add a new baseline entry as long as the baseline gets shorter overall, and names it; a finding to ignore for good, or a baseline that would not get shorter, becomes an ignore rule in
phpstan.neononly after the human allows it. - Contributors are told to turn a rule that is broken twice into a check, and the validator now checks that README and docs cite no ADR or PR numbers and no scratch files.
0.7.0
-
Breaking, for 0.7.0: the suite is rebuilt around one run of decision points, with all state in your tracker and forge.
/continuous-refactoringnow leads from your open refactoring tickets to one opened merge request and, at every step — reconcile, Track choice, scan, filing tickets, selecting, design, implementation, merge request — shows what it found, the options and one recommendation. By default you decide each time; say in the call that it should do the run itself ("do it yourself"), or mid-run "carry on yourself from here", and it takes its own recommendations. The call also takes a Track, a ticket or a restriction ("only the Rector tools") in your own words. The suite keeps no state of its own any more: the config file, the bookkeeping document (local and remote),Ticket-create-mode,MR-create-modeand the Track cadences are gone, and so are the limits of two open merge requests and five open candidates. Tickets are found by their subject instead of a fixed label or title, a ticket you wrote yourself is picked up through a Candidate mark or by naming it, and a Track is scanned once — afterwards its tickets are the record. Where your project has its own skills for planning and implementing, a run recommends those and uses the suite's procedures as a fallback. Housekeeping is now one standing ticket made from a template in your repository, with a rhythm you choose, refactoring ideas left on it as comments, and its own command/continuous-housekeepingthat can be scheduled and that an agent may start by itself. The suite is two skills,continuous-refactoringandcontinuous-housekeeping; the nine others are removed. The operations indocs/agents/issue-tracker.mdchange their cut: Search is new and required; Rejected, Blocked by and Housekeeping are new and optional; Bookkeeping, Filed date and Comment author and time are removed.A project onboarded on 0.6.0 needs three steps. (1) Run the onboarding again: call
/continuous-refactoring, which adds Search to your## Refactoring operationssection and removes the bullets that no longer exist. (2) Delete the suite's old files under.scratch/refactor/—config.md,bookkeeping.md,merge-requests.mdand the folderout-of-scope/; they are no longer read. Tickets kept as local Markdown files under.scratch/refactor/issues/stay. To keep your old rejections where they are instead of deleting them, name that folder under Rejected in the section (a rejection that should come back by itself once a PHP version is reached needs a lineBlocker: PHP >= X.Y). Where the bookkeeping lived in a tracker issue, close that issue. (3) Remove the symlinks of the removed skills from your skills folder:refactor-loop,refactor-scan,refactor-prioritize,refactor-design,refactor-implement,refactor-learn,continuous-safety-net,continuous-guardrails,continuous-investigation. Nothing is migrated; the first scan of each Track rebuilds the worklist as tickets. -
The Housekeeping ticket's date line, template line and title are described by what they hold, not by a fixed wording: the onboarding words the Housekeeping bullet itself, and later runs read the due date and the template from the ticket in whatever words it states them.
-
The suite no longer sets or reads the triage labels
needs-infoandready-for-agent. Whether a ticket waits for an answer or is ready to work is read from its comments, so it works in a tracker without them. It stays compatible with other engineering skills, such as those of mattpocock/skills, and needs none of them. -
The onboarding now ends the run. Instead of offering to go on in the same call,
/continuous-refactoringreports the onboarding as complete, points out the changes it left in the working tree (the tracker file) and recommends committing them and calling the skill again. -
The onboarding now tries its search and merge-request commands before it shows you the summary, not after writing the tracker file. When one fails, for example because your installed
glaborghis older, the onboarding asks about a working variant at that point, so the summary you confirm already contains commands that work and no second confirmation follows after writing. A run on its own takes a working variant it found itself; without one, it writes nothing and names the open question.
0.6.0
- Breaking: the suite's state no longer lives in a committed
docs/refactoring/folder. Your create-modes (Ticket-create-mode,MR-create-mode) and the pointer to the bookkeeping now sit in.scratch/refactor/config.md, and by default the bookkeeping itself in.scratch/refactor/bookkeeping.md— files the suite writes but never commits, branches or opens a merge request for (whether they go into Git, and how they reach another machine, is up to you). Focus areas and refactoring goal are now two lines you add toAGENTS.md. A create-mode the config doesn't state reads as the safe value (ask-each-time,human-opens), and candidate merge requests are no longer opened as drafts. An existing project runs the onboarding again: it moves the state fromdocs/refactoring/into the new layout and, after you confirm, removes the old files. The Housekeeping checklist stays atdocs/refactoring/housekeeping-template.md. - The suite now works with any issue tracker that
docs/agents/issue-tracker.mddescribes, not only GitHub, GitLab and local Markdown files. Skills read a handful of named operations from a new## Refactoring operationssection in that file instead of deciding by the tracker's name, and tickets and merge requests may live in different systems (for example Redmine tickets with GitLab merge requests). Onboarding offers a tracker the file already describes as its own answer, lets you describe another one in the interview, and no longer falls back to local files silently. A project onboarded earlier needs the new section:/continuous-refactoringstops with a message until the onboarding has been run again, which adds it. The suite no longer prescribesCloses #<n>itself — the GitHub and GitLab templates carry it. - New: remote bookkeeping. Instead of local files, the bookkeeping can live in a tracker issue or anywhere else your project describes, and any machine with access to it picks the state up without a commit. The suite fetches the bookkeeping before a pass and stores it after every write; where it lives and how that is done is written in your project, as a Bookkeeping entry under
## Refactoring operationsindocs/agents/issue-tracker.md. The GitHub and GitLab templates bring that entry: an issue whose body is the bookkeeping, with learned rejections as comments on it. Onboarding offers to create such an issue, to adopt an existing one, or "as this project describes it", for which it proposes a description from your project's own files. The last write wins; bookkeeping that can't be fetched stops the pass and is never replaced on its own. - A Safety Net or Guardrails pass no longer picks up structural candidates: an issue labelled
refactor:candidatethat isn't a tooling-tree node's is now worked only in an Investigation pass, and the closing report says how many are waiting. Candidates you labelrefactor:priorityare still taken by any pass. - The bookkeeping document's top-level
Pending candidatesfield is gone: every candidate in flight is now tracked in its own Track'sOpenlist.## Investigationgains anOpenfield for that, the same shape Safety Net's and Guardrails' already use, holding one entry per in-flight candidate of its own (structural, PHPStan baseline-shrink, or externally-labeled) — up to two, as the suite-wide two-merge-request cap allows.refactor-designappends the entry,refactor-learnremoves only the one for the candidate that resolves, andrefactor-designwrites no bookkeeping for a tooling-tree node.refactor-scanresumes from the selected Track'sOpenalone, so an Investigation candidate is resumed only during an Investigation pass, never mid a Safety Net or Guardrails one. An existing document that still carriesPending candidatesneeds no change — the line is ignored. One edge changes: on a tracker without native labels, a hand-filedTooling tree: <Name>issue interrupted between design and implementation is ranked again on the next pass instead of being resumed unconditionally. - A flagged candidate (
needs-info) now self-confirms when a human's newest comment on the issue plainly agrees with the stated default: the suite swaps the labels itself instead of waiting for you to also flipneeds-info/ready-for-agentby hand. A comment proposing something else, or raising a further question, still leaves it flagged — the suite nudges once instead of skipping silently forever, but never applies an alternative on its own. refactor-prioritize's "a proposable tooling-tree node is a strong default recommendation" now applies only when every proposal in the pool is itself a tooling-tree node. The moment an issue-backed candidate (structural, PHPStan baseline-shrink, or externally-labeled) is ranked alongside a gate likestructural-scan, no default applies to either side — both compete purely on Heat, Leverage, Tooling pressure, and Risk. Previously the default let a permanently-or-long-proposable gate out-rank an already-filed candidate indefinitely, regardless of the candidate's real merit.- The one-time exception in Track selection is gone: once the Safety Net is in place, no Track gets a forced turn any more. The scheduler goes straight to its ordinary order — Guardrails' first scan, Housekeeping's first cycle, Guardrails' backlog, then Investigation — and the Safety Net pass that finishes the foundation tells you that Guardrails, Housekeeping and Investigation can now each be run directly by naming the Track (e.g.
/continuous-refactoring investigation). An Investigation candidate already in flight no longer takes passes away from a due Housekeeping or a workable Guardrails node. - A Safety Net or Guardrails scan now hands its own fulfilment judgement to the tooling-tree script and records the script's complete ordered list — blocked nodes included — as the Track's
Open, instead of reading a state the script no longer detects. Fixed alongside: a target whosebookkeeping.mdhad a## Safety Netsection but no## Guardrailssection yet was read as having every Guardrails node already in place; a missing Track section now means that Track never ran. A seed file the script cannot read now stops it with an error instead of being silently replaced by the bookkeeping state.
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...
0.4.0
0.3.0
- Fixed two tooling-tree parser false negatives (
phpstan-level-0and Rector's set-name casing)
that could report an already-adopted node as unfulfilled. (#48) refactor-scannow proposes PHPStan baseline-shrink candidates: incrementally reducing an
existing baseline file instead of leaving it frozen forever. (#49)- Fixed a staleness bug: the bookkeeping write now reads a fresh
origin/mainimmediately before
writing, instead of a snapshot that could be several commits behind. (#50) - Fixed the resolved-gate cascade to correctly propagate through a rejected required ancestor,
instead of leaving descendants stuck — including the same fix applied tocomposer-audit's own
fallback gate. (#51, #55) - Added a
Refactoring goalfield that steers which structural candidates the loop searches for
next. (#53) - Fixed Psalm-equivalence detection to respect the documented co-presence rule instead of a
stricter, undocumented one. (#57) - Added the
continuous-housekeepingskill: a separate, recurring maintenance sweep (default
weekly) for dependency currency, tooling-deprecation cleanup, and documentation sync — plus a
Housekeepingfield tooling-tree nodes can contribute to. (#58) - Added
docs/FAQ.md, answering recurring questions about the suite's own design decisions,
linked from the README. (#59) - Added a
CHANGELOG.mdfragment-file mechanism: noteworthy changes drop a.changelog.d/*.md
fragment (enforced by CI via theno-changeloglabel escape hatch), consolidated into
CHANGELOG.md— and the fragments deleted — at release time. (#60)
0.2.0
- Folded native-tracker in-flight bookkeeping into the candidate's own branch instead of a shared
file, removing a recurring source of merge conflicts. (#40) - On a native-label tracker,
refactor-designskips the now-redundant Pending-candidates write.
(#41) - Dropped the
rector-early-returntooling-tree node, folding its scope into
rector-code-quality. (#45) - Candidate merge requests now open as draft until the fold-in bookkeeping lands. (#46)
- Added a
psr-4tooling-tree node for app-source autoloading. (#47)
0.1.0
Initial release.
- The
scan → prioritize → design → implement → learnorchestrator loop, plus the generic
(language-neutral) tooling tree and itsstructural-scangate. (#8, #9) - PHP tooling-tree specialization: structural-scan leaves (editorconfig, composer, ci-runner), an
is-php-projectrecognition gate, the PHPStan adoption chain (levels 0–10, baseline shrinking,
Psalm mutual exclusion), the Rector rule-set family, and a PHP-minimum-version floor precheck.
(#6, #7, #21, #23, #24, #26, #27, #28, #29, #30, #31) - Recommended-edge gating and a CI-gating self-wire, so a node only proposes once its
prerequisites are actually adopted, not merely present. (#19, #20) loop-configbecame a one-time human setup interview instead of guessing the tracker/create-mode.
(#32)- Human-readable tooling-tree node names, a per-pass closing report, and Learnings entries
recording what a past attempt got wrong. (#13, #14) - A round of fixes from the suite's first live dogfooding run against a real target repo:
composer-audit timing, config caching, PHPUnit layout detection,.scratchcleanup,
refactor-prioritize starvation, and a further batch of reviewer-loop findings. (#12, #15, #16,
#17, #18, #36) - Test harness (Tiers 1–5): fixture-driven regression coverage for the tooling-tree parser,
trigger tests, and its own CI gate. (#1, #2, #3, #10, #22) - Every skill's
SKILL.mdradically shrunk for token economy, detail moved intoreferences/.
(#33) - Repo prepared for going public. (#37)