Iterate mode
This workflow defines PM orchestration, state, draft selection, and reporting for Iterate runs. Specialist workflows own research, writing, and review; Output layout owns generated paths.
Core terms
| Term | Meaning |
|---|---|
| Iteration | One writer draft or revision followed by mechanical validation and one independent review. |
| Best draft | The eligible draft that preserves verified guidance and resolves the most consequential supported findings. |
| Iteration budget | A ceiling of 1, 2, or 3 iterations for this run; it is never a target to spend. |
| Review context | Optional approved context frozen for the run under Review context. |
| Preservation ledger | The continuing record of verified source decisions for an existing page. New pages do not use one. |
Manifest contract
The run manifest is drafts/run-manifest.json in the cache document root,
.authoring-kit-cache/documents/<source-directory>/<document-key>/. Drafts, draft review reports, frozen
review contexts, the preservation-ledger working copy and reviewer scratch sit beside it in drafts/;
none of it is committed. The PM never writes the manifest: update-manifest.mjs
creates and updates it (the subcommands are in the pipeline sequence below), validates the whole manifest
before writing, and writes nothing on ok: false. Its exact version 1 contract is
iterate-manifest.schema.json. Do not read the schema or
another manifest to learn the format.
Rules the script enforces:
- A fresh history is schema version 1; each batch appends one
runsentry, and each reviewed draft oneiterationsentry. Earlier runs and iterations are never rewritten. - The draft hash is recomputed after review and must equal the snapshot’s
sourceHash, so a draft changed after review is refused. substantiveFindingsis the list of finding IDs in that report, for resuming and loop control; it is not a count or a quality metric.- The writer and reviewer never read the manifest.
- The cache is not committed and
npm run cleanremoves it. A lost cache (or a new clone) loses a half-finished run: the Iterate run restarts.
Stale draft checks
Before reusing a recorded review, run
node authoring-kit/scripts/check-fresh.mjs --mode=iterate --manifest=<run-manifest> --context-hash=<current frozen hash or null>.
For each iteration it reports fresh and any failed checks:
- The draft’s recomputed hash equals
contentHash. - The recorded rubric version is the current one in
review/config/content-quality-rubric.config.json. - The iteration run’s review-context hash equals the current run’s frozen hash, including
null. - The paired report still exists and contains a matching version 3 reviewer snapshot.
allFresh summarises. An ok: false result means the manifest is unreadable or inconsistent; correct
it first. If any check fails, copy the candidate to the next numbered draft and obtain a fresh review. Never
overwrite an earlier draft or attach a second context to it.
Resolve review context
Before review, combine the document backlog located by preflight (reviewContext) with any request-supplied context,
normalise it as the review-context contract describes,
validate it against the review-context schema,
and reject unknown fields or duplicate IDs. Do not discover context in ledgers, reports, research,
manifests, or writer notes.
When effective items exist, write one normalised snapshot to
<cache document root>/drafts/review-contexts/<run-id>.json, hash it, and freeze both path and hash for the run. Otherwise
record null for both. A context change during execution makes the run stale.
Pipeline sequence
Documents are processed sequentially, never in parallel.
-
Parse the request. Record paths, focus areas, review context, and the iteration budget. If no budget is supplied, ask for 1, 2, or 3 and state that 1 is the default. Run
node authoring-kit/scripts/preflight.mjs <source-path>for each document: it derives the document key, applies the output-layout collision check, and reports the research state, review-context paths, and routed rubric. Stop onok: false. Then runnode authoring-kit/scripts/context-files.mjs scaffold <source-path>to create any missingbacklog.mdorresearch-context.mdplaceholder; it never edits a file that exists. Report the files it created. -
Select the authoring method. Choose by path and record
neworexistingsource state:Page Method Source state Component MDX exists author-component-page existingComponent MDX does not exist author-component-page newGuideline MDX exists author-guideline-page existingGuideline MDX does not exist and approved first-party policy is supplied author-guideline-page newStop a new guideline run when no approved first-party policy exists. External research cannot establish MDS policy.
-
Set the run. Run
node authoring-kit/scripts/update-manifest.mjs start-iterate --source=<source-path> --workflow=<author-component-page|author-guideline-page> --source-state=<new|existing> --budget=<1|2|3> [--research=<research-path>] [--preservation-ledger=<cache-ledger-path>] [--context=<frozen-context-path> --context-hash=<hash>]. It creates the manifest or appends a run to the existing one (a resume), takes the run ID from the UTC clock, and returns it with the next draft number, the cache draft path andreviewerScratchPaths, the two scratch report paths for that draft’s review. Omit--preservation-ledgerfor a new page; otherwise it is<cache document root>/drafts/preservation-ledger.md. The research file and ledger do not exist yet; only their paths are recorded. -
Research. Run for component pages unless the user says otherwise. For any other page, ask the user whether they want research on the topic before drafting, and run it only on a yes; with an existing
research.md, ask whether to reuse it, extend it, or skip it. With noresearch.md, delegate acreate. Otherwise reuse the file as it is, and never replace it. If the user asked for targeted research (for example keyboard navigation), run anextendon that topic before drafting. If preflight reports the researchstale(research-context.mdis newer thanresearch.md), tell the user and offer anextendwith no topic before continuing. Delegate under the researcher brief, wait for its returned handoff, and record_ak/<document-key>/research.md. If the handoff lists contested points, give the user the ready-to-paste text at the end of the research step, or straight away when a draft depends on the claim; the writer treats a contested claim as unverified. Offer each as anOpen questionsentry and say you will add them toresearch-context.mdif they ask (Context files); add nothing otherwise, and never offer a[decision]placeholder. -
Extract component API. For a component page, run
node authoring-kit/scripts/extract-component-api.mjs <slug>before every writer brief. Pass the output or its unavailable result to the writer. A page can document several packages (Tabs istab-barandtab; Select isselectandoption): the script readscomponent-packages.jsonbeside it and prints a section for each, so pass all of it. When it reports a part as not covered, or exits 1 for a compound page that is not listed, tell the user the part is unverified rather than guessing; the fix is a map entry, which is a human edit. -
Iterate. Delegate to the writer under the writer brief, wait for the draft, run the mechanical gate, hash the exact bytes, then delegate one fresh reviewer under the reviewer brief, passing the routed rubric path, a snapshot timestamp (run
date -u +%Y-%m-%dT%H:%M:%SZonce, just before dispatch, and reuse the value for a correction), and the first of the draft’sreviewerScratchPathsfromstart-iterateor the previousadd-iteration. Accept the report at the returned path withnode authoring-kit/scripts/update-manifest.mjs add-iteration --source=<source-path> --run-id=<runId> --draft=<draft-path> --scratch=<assigned-scratch-path> --timestamp=<review-timestamp>, which copies it todraft-<nnn>-review-report.md, records the iteration, derives the finding IDs, and validates. Apply Loop control. A correction uses the second scratch path. Iterate never invokes the synthesiser. -
Finalise. Select the best draft, assess Coverage, and run the deterministic finaliser below.
-
Report. Use the final-report contract below.
Mechanical validation gate
After every writer step and before review:
- Run
node authoring-kit/scripts/check-page-quality.mjs <draft-path>. - Errors block review; notes do not. Send exact errors to the writer for a corrective edit on the same file. A corrective edit does not spend another iteration.
- Allow at most two corrective passes. If errors remain, stop and report them.
- After a clean gate, hash the draft and pass the validation result plus hash to the reviewer.
- Accept only a report, at the returned scratch path, with one matching version 3 reviewer snapshot,
including
model, and complete evidence fields. Runcheck-review-report.mjson it with--started-at=<review-timestamp>and--role=reviewer; its warnings are advisory, as in Review-only.add-iterationrecomputes the draft’s hash after the reviewer returns and refuses a draft that changed after review.
Loop control
Apply the first matching condition after each review:
| Condition | Decision |
|---|---|
| No supported substantive finding remains (known items do not count) | Stop. |
| Every remaining substantive finding needs a human decision or unavailable evidence | Stop and list what is needed. |
| The iteration budget is exhausted | Stop and report unresolved findings. |
| A substantive finding can be fixed from available evidence and budget remains | Continue from the best draft with that evidence. |
Do not stop or continue because a rating changed or because of the number of findings. A known
item never drives another loop and never blocks readiness, unless the reviewer marked it not applied and counted it as a finding.
Best-draft selection
An existing-page draft that drops a verified rule or decision cannot displace one that preserves it without explicit user approval. Use the preservation ledger. For a new page, compare the approved brief, research, and immutable draft history.
Among eligible drafts, compare the actual passages behind substantive findings. Prefer the draft that resolves consequential problems without introducing comparable problems or unsupported guidance. A missing finding in a later report is not proof of resolution. If no supported improvement separates drafts, retain the earlier one. Record the passages and findings that determined the choice; never choose by rating or finding total alone.
Coverage and readiness
The PM assesses Coverage from the research file and selected draft:
complete: cite the passage addressing every relevant Decision topic (a deliberate statement that MDS publishes no rule counts; see the rubric’s Coverage table);gaps: list every relevant topic withno passage found;unassessed: explain why no usable research file exists.
Readiness follows this order:
| Condition | Recommendation |
|---|---|
| Mechanical errors, unapproved guidance loss, or substantive findings (not known items) remain | Needs revision. |
Coverage has gaps | Needs coverage work. |
A consequential question is unresolved or Coverage is unassessed | Needs human verification. |
Checks pass, guidance is preserved, no substantive finding remains, and Coverage is complete | Ready for manual review and promotion consideration. |
Promotion remains a human step. Never offer to promote the file.
Finalise
Run:
--draft and --report are the cache draft and its paired cache report. The script verifies the
reviewed bytes and snapshot, applies only the documented path-depth changes, and writes the best-draft
directory ak-<document-key>-best-draft/: <source-filename>, its score-free content-quality.json,
review-report.md (the paired report, its heading path rewritten to the best-draft file) and, for an existing page, preservation-ledger.md. A re-finalise
replaces the whole directory. The snapshot’s sourcePath is the best-draft file, because that file is
what the recorded hash covers; a promoted draft is reviewed again as the live page. Its
reviewProvenance points at review-report.md with reviewCount: 1. It never writes the live source
and commits nothing on failure. Treat a non-zero exit as a failed finalise.
After a successful finalise, record the outcome with
node authoring-kit/scripts/update-manifest.mjs finish-iterate --source=<source-path> --best=<iteration> --best-reason=<text> --stop-reason=<text> [--unresolved=<F1,F2>] [--final-draft=<selected-cache-draft-path>].
It sets bestDraft, stopReason, unresolvedFindings (finding IDs, no commas inside an ID) and
finalDraftPath, validates, and writes only on success.
Runs and resuming
A fresh history starts at draft-001. A resumed run requires a valid schema version 1 manifest
with at least one iteration, appends a new run ID, continues numbering, and carries the best draft
forward. Apply the stale checks before trusting any earlier review. The user must explicitly
request every additional batch.
Final report
Include:
- File, display rating, reason, lens assessments, readiness, next action, and report link.
- The committed best-draft directory, and the cache paths of the working drafts and run manifest for local inspection (not committed).
- Supported improvements and remaining substantive findings, with passages and report IDs.
- Strengths and optional polish.
- Best-draft reasoning and links to every iteration report.
- Every review-context ID and disposition, the known items excluded from the rating, and any
ready-to-paste
backlog.mdentries you propose. Add them only if the user then asks (Context files); a person decides. - Coverage status with topic citations or the reason it is unassessed.
- One research line from preflight’s
research.bytesand the file, with no threshold or gate, e.g. “Research: 14.2KB, created 2026-10-07, 3 updates, 6 Decision topics, 1 contested, last full check 2026-10-07”, plus any contested points as ready-to-pasteOpen questionsentries forresearch-context.md. - Proposed business examples and implementation proposals; for existing pages, preservation-ledger changes and any approved omissions.
- Iteration budget and usage, reviewer model, and rubric version.
- Manual next steps for promotion and deliberate ledger replacement or append, which the user runs by hand (README).
- Last, a numbered Decisions I need from you list. One item per decision, each saying what you ask, your evidence-backed suggestion when you have one (labelled unconfirmed), and what you would add and to which file if they answer or ask. Cover, in this order: an open finding that needs an owner decision; each contested point; each proposal not in the draft, to approve or drop; each open question for confirmation. Say that answers can be given in one reply, that you will add entries only on request, and that a further iteration can follow. Do not repeat an item the report already lists; point to it. Omit the list when nothing needs a decision.
Never commit, push, publish, promote a draft, edit live page content, or clean generated history.