Skip to content

0.5.0

Choose a tag to compare

@Art4 Art4 released this 24 Sep 17:01
· 229 commits to main since this release
2f201b6
  • 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 on is-php-project:
    has-real-dependency (the project has a real, non-platform dependency) gates composer-audit,
    phpstan-baseline-empty (the current PHPStan baseline is empty) gates every PHPStan level above zero,
    and phpstan-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-refactoring is 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-agnostic refactor-loop skill that requires a Track and aborts without one;
    continuous-safety-net, continuous-guardrails and continuous-investigation delegate to it, and
    continuous-housekeeping owns Housekeeping's own process with its three reference files. Only
    continuous-refactoring is 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-scan now judges a Safety Net Track node's Fulfilment check against its
    own Purpose statement (an agent walking the tree), instead of trusting tooling_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.md gains a ## Safety Net section (Cadence, Last scan, Open, Out-of-scope),
    replacing the old Fulfilled nodes/global Pending candidates fields for this Track's own nodes;
    refactor-learn writes into it symmetrically — merge removes an entry from Open, rejection removes
    it and writes both out-of-scope/<slug>.md and an Out-of-scope pointer. A repo on the old
    bookkeeping.md shape runs a normal pass, unaffected.

  • Guardrails Track: refactor-scan now 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 on structural-scan/php-safety-net themselves (composer-audit, phpmd,
    coverage-floor, php-minimal-version, phpstan-level-6 and above, phpstan-deprecation-rules,
    semgrep) — proposed only once the Safety Net has closed. bookkeeping.md gains a ## Guardrails
    section (Cadence: 60, Last scan, Open, Out-of-scope), independent of ## Safety Net;
    refactor-learn writes into it with the identical merge/rejection symmetry
    safety-net-write.md already established. A repo mid-migration — ## Safety Net already closed, ## Guardrails never run — runs a normal pass, unaffected.

  • Dev-repo CI: tier3 (Ground Truth) and the roadmap fixture matrix no longer gate test-harness.yml.
    Both asserted against tooling_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 via fixtures/harness/run.sh's existing --opencode flag, the same
    local-only/advisory posture tier4's non-deterministic parts, judge, lift, agent-loop, and
    decision-gate-bypass already use. tier1/tier2 are 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.md step 0b,
    skills/continuous-refactoring/references/track-scheduler.md) computes each due, Open-empty Track's
    overdue_ratio = (today − Last scan) / Cadence and hands the highest-ratio one to refactor-scan as
    an explicit input; a tie (or two Tracks that have never run) falls back to the fixed order Safety Net

    Guardrails > Housekeeping > Investigation. A Track with non-empty Open still 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-prioritize step 1) was already Track-agnostic and needed no change.

  • Investigation now has its own bookkeeping.md section (## Investigation, Cadence/Last scan
    only — no Open/Out-of-scope, a structural candidate's own state still lives on the issue tracker /
    merge-requests.md as before) and joins the Track scheduler's real competition
    (skills/continuous-refactoring/references/track-scheduler.md). Its Cadence is 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 > Housekeeping

    Investigation. 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-housekeeping skill is retired. Its process — due-check, reconciliation
    against fulfilled nodes, checklist assembly from housekeeping-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.md gains a ## Housekeeping section (Cadence, Last scan only — no
    Open/Out-of-scope; swept content stays in housekeeping-template.md, unchanged) — a hybrid of
    Investigation's shape and Safety Net's/Guardrails' own: Cadence defaults to 7 (days, unchanged from
    today's default) and is hand-editable, unlike Investigation's permanent continuous, but there's no
    in-flight Open list, 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-housekeeping entry point. No standalone continuous-housekeeping
    skill remains; its references/ (cadence interview, housekeeping-template.md's own format doc) moved
    under continuous-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 own Open first 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 candidates state — 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
    Open of its own) whether Pending candidates still 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 Open node 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 leaves Open with 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 of Open (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 Net Open is 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 workable Open node is selected ahead of Investigation; Guardrails with
    Open non-empty but nothing workable yields, its Open stays 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-empty Open — it reads only whether each section exists, not whether its Open
    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 a Housekeeping field, 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. The Fulfilled nodes bookkeeping field is
    retired: no skill reads or writes it any more, and a bookkeeping.md that still carries the old field
    is left untouched and ignored. Covered by two new advisory agent fixtures:
    php-housekeeping-hand-adopted-guardrails and php-housekeeping-old-schema.

  • skills/refactor-scan/references/tooling_tree.py no longer detects anything: the hardcoded
    dependency-name detection and the forward-simulating roadmap output are deleted, and the script now
    takes a fulfilment seed (--seed, or the Refactoring Notes' fulfilled-set.json) or derives state
    from bookkeeping.md's Track sections, computing the tree's graph logic only — the ordered Open
    backlog, workable and withheld nodes with reasons, rejection cascades, PHP-floor findings, and the
    merge-request outlook (--unblocked-by). The harness's roadmap tier and the eight
    expected/roadmap.json fixtures are removed with it; the drift check comparing the manual tree-walk
    fallback with the script's graph logic continues as scripts/drift_check.py, advisory and run
    manually (never collected by CI's test_*.py discovery).

  • Safety Net and Guardrails Track Open entries now record their issue number (- <slug> (#<issue>)) as soon as refactor-design files it, instead of staying unlinked until a merge request opens or merges — closes a bookkeeping gap that previously forced refactor-scan to rediscover already-filed tickets by searching instead of reading the link.

  • Cross-skill citations inside skills/** (one skill's SKILL.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.py now checks the new form and flags any reappearance of the old one.

    safety-net-track.md/guardrails-track.md no longer imply a node's tree-doc file can be derived from its slug alone (php-tooling-tree/<node>.md) — a multi-node file like rector.md/psalm.md broke that assumption and sent an agent searching for a file that doesn't exist under that name. Both now point at php-tooling-tree.md's own per-node Full definition pointer instead, which always names the right file.

  • php-structural-scan renamed php-safety-net. CONTEXT.md gains Onboarding (the bounded
    phase before structural-scan opens) and its narrower Safety Net, plus a new Signal wave:
    composer-audit/phpstan-deprecation-rules move out of the PHP Safety Net into the Signal wave
    (gated on php-safety-net closing, in addition to their existing required parent, so a rejected
    parent still permanently closes them); phpmd/coverage-floor/php-minimal-version/
    phpstan-level-6 join the Signal wave the same additive way; semgrep is fully repointed onto
    php-safety-net alone (its old composer required parent dropped); the generic root's
    secret-detection now waits for structural-scan itself to open instead of proposing from the
    very first pass. composer-audit/semgrep also gain a Housekeeping-line fulfilment fallback (a
    committed housekeeping-template.md line naming the node, no CI run required).

  • phpstan-level-0 detection now falls back to phpstan.neon.dist when phpstan.neon is absent
    (PHPStan's own auto-discovery order, already honored elsewhere in this tree for
    phpunit.xml.dist/psalm.xml.dist/phpmd.xml.dist). phpstan.neon still wins when both files
    exist. Fixes a false "no level configured" report on targets that only ever committed the .dist
    file.

  • A Track's Cadence can 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 older bookkeeping.md still reads as days, and the loop now writes its defaults as 90 days, 60 days and 7 days.

  • Docs refresh: README now explains the four Tracks (Safety Net, Guardrails, Housekeeping, Investigation), the dispatcher/refactor-loop split and the two-merge-request cap, and indexes all docs. New docs/playbooks/tracks.md (how Tracks are selected, the one-time exception, working open items, overrides) and docs/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 no bookkeeping.md the 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.md last) and the invocation ends with a closing text: commit the files, then run /continuous-refactoring again 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 lists gh label create commands for GitHub). continuous-safety-net, continuous-guardrails, continuous-investigation and continuous-housekeeping now abort with a pointer to /continuous-refactoring on a project that was never onboarded. The tooling-tree node loop-config ("Refactoring Config") is renamed onboarding-setup ("Onboarding Setup"); targets with an old-style loop-config candidate already open are not migrated.

  • The bookkeeping.md the 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 applies php-tooling-tree/psr-4.md's own judgement call
    before treating a non-empty unwired_entry_points result 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 nodes bookkeeping field is removed from the documented schema and from every fixture and harness check. Nothing changes for a bookkeeping.md that still carries it: the block is ignored, and can be deleted by hand at any time.

  • New Ticket-create-mode setting (autonomous, or ask-each-time to 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 with ask-each-time it 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 means autonomous, so existing targets behave as before.

  • Create-mode is renamed MR-create-mode (values unchanged) — it only ever governed how merge requests get opened. An older bookkeeping.md with the old name is still read, and renamed on its next bookkeeping write.