| name | quality |
| position | none |
| description | Write a SLICE's quality lens as a grounding doc (quality.md) — a short statement of what "good" means for the slice plus a table of checkable gates (dimension / bar / how checked), drawn from the profile's NFR gates that apply and the slice's functionalities' rules, never invented. The MIDDLE of the NON-FUNCTIONAL realize pipe (architecture → quality → run), run on a shaped slice. Reads the hub from the spine (functionality grounding + profile), never another lens. Writes only the slice's quality lens. |
| user-invocable | true |
quality
Write a shaped slice's quality lens as the grounding doc quality.md: what "good" means for
this slice, and the checkable gates it must clear. The gates are drawn from the product profile's
NFR gates that apply to the slice and from the slice's functionalities' own rules, made checkable —
never invented. /quality reads the slice's hub — its functionalities' grounding docs plus the
profile (both from the spine) — and never another realize lens.
Pipeline position: none. /quality is the MIDDLE of the non-functional realize pipe (architecture
→ quality → run): it runs on the branch /arch already started, injects no start-change head and no
close sequence, stops when its work is done, and leaves the branch for /run. The close belongs to
/run. It writes the persistent product model (the slice's quality lens) on the already-started branch.
Compiled From
This play was compiled from the quality ICE (reference/ice.md) by play-editor (#466 Batch C).
Intent defines constraints (C1–C11) and failure conditions (F1–F12); the expectation defines success
scenarios (S1–S6), a Done means (D1–D4, baked to stop-condition.yaml), and one recovery entry per
failure condition. To modify this play, update reference/ice.md and recompile with play-editor.
Do NOT edit this file manually.
(#467 Batch B) checkpoint upgraded to a conditional learned gate; see gate-config.md.
Role
You are the orchestrator. You own the workflow and step order. You delegate the domain work —
authoring the quality lens grounding doc — to the product-os-keeper agent via a JSON contract over
files on disk, and you run the mechanical checks (readiness/hub resolution, the shape linter, the
content-quality eval, grounding + coverage, the allowlisted apply, the verify) through bundled scripts
and an isolated judge. You never write the lens yourself, and you never persist before the single
checkpoint's gate resolves (C10) — a typed approval, a recorded config skip, or a recorded policy
auto-pass.
Forbidden: hand-writing the lens or a decision; writing anything other than this slice's
quality.md, its machine sibling quality-gates.yaml, and a decision (C2); reading or grounding on
another realize lens (C7); inventing a gate with no profile gate or functionality rule behind it
(C5); persisting by any route other than scripts/apply_quality.py; persisting before the
checkpoint gate resolves; closing COMPLETED without the stop-condition verdict held (C11).
Agent boundaries:
| Agent | Domain | Skill it invokes | Phases |
|---|
product-os-keeper | Author the slice's quality lens (intent + gates) from the hub — the profile's NFR gates that apply + the functionalities' rules | author-quality-lens | Draft |
product-os-keeper is the single domain agent this play uses (1 of the ≤5 budget). The
content-quality judge always runs as an isolated, clean-context sub-agent (optionally on a configured
different model) — never the orchestrator's own context.
Pre-flight
| Check | Constraint | Action on Failure |
|---|
Resolve config + product_base (.garura/core/config.yaml) | — | Hard halt |
Resolve grounding-eval.judge (optional model override) | C4 | Default: sub-agent on the session model |
Slice ready + hub resolves (check_ready_slice.py) | C1 | Hard halt (REC1) |
Resolve the pre-flight facts mechanically with the bundled resolver:
python3 scripts/preflight.py --play quality --config .garura/core/config.yaml
Then resolve the slice and its hub from the spine — the readiness gate every realize lens shares:
python3 scripts/check_ready_slice.py --product-base <product_base> --slice <slice-id>
It asserts the profile is set (from the spine), resolves the slice record, and resolves every
functionality_ref through the spine to its functionality.md grounding doc — the hub. If the slice
is absent, a functionality does not resolve, or the profile is not firmed, hard halt (C1/REC1).
The run's working root is <working> = {stm_base}_realize/quality/ — the draft, snapshots, apply
manifest, and status markers all live under it (the stop-condition gate evaluates against it).
Right after the resolver, record the session identity stamp's start marker (#463 — soft-fail, never
a halt):
python3 scripts/session_stamp.py --phase start \
--marker "{stm_base}_realize/quality/status/session-stamp-quality.json" \
--cwd "$(pwd)" --branch "$(git branch --show-current)"
Resume check: if {stm_base}_realize/quality/status/<slice-id>.json exists, resume — skip
completed steps, reset any in-progress step to pending, continue.
Task DAG
Create ALL tasks immediately after resolving config — before any domain work.
[T1] Draft the lens blockedBy: []
[T2] Validate the draft blockedBy: [T1]
[T3] Checkpoint (approval) blockedBy: [T2]
[T4] Persist blockedBy: [T3]
[T5] Verify persisted blockedBy: [T4]
[T6] Scenario Validation blockedBy: [T5]
[T7] Close blockedBy: [T6]
Mark each task in-progress before its step and completed right after its eval passes.
Workflow
Phase: Draft
Step 1 — Draft the lens · Owner: product-os-keeper · Depends on: pre-flight
The agent invokes author-quality-lens to draft the slice's quality.md (the intent + the gates,
per the Quality lens template) AND its machine sibling lens/quality-gates.yaml (#462 — one binding
card per Gates-table row) from the hub (the functionality grounding docs + the profile's NFR gates),
plus a quality-manifest.yaml (the grounding map) and any material decision:
{
"task": "author the slice's quality lens (intent + checkable gates) from its hub; ground every gate in a profile NFR gate that applies or a functionality rule",
"inputs": { "slice_ref": "<domain>/<slice>",
"slice_file": "<slice record>",
"functionality_groundings": "<from check_ready_slice>",
"profile": "<spine profile>", "product_base": "<product_base>",
"lens_rel": "product-os/<domain>/slices/<slice>/lens/quality.md" },
"outputs": { "draft_dir": "<working>/draft/", "manifest": "<working>/draft/quality-manifest.yaml" }
}
The skill reads the hub read-only and writes only the draft (the quality.md, the manifest, any
decision).
Step 2 — Validate the draft · Owner: play · Depends on: Step 1
Run the guards over the draft before the checkpoint — shape first, then content, then grounding.
python3 scripts/lint_grounding.py --doc <working>/draft/product-os/<domain>/slices/<slice>/lens/quality.md
python3 scripts/validate_quality.py --draft <working>/draft --manifest <working>/draft/quality-manifest.yaml --slice-file <product_base>/<slice_file>
Then run the content-quality eval over quality.md: spawn an isolated, clean-context sub-agent
handed the judge prompt (standards/rules/grounding-eval.md), the doc, and the Quality lens
per-section guidance, on the model from grounding-eval.judge.model. Gate the verdict:
python3 scripts/grounding_gate.py --verdict <verdict.json>
SE-1 (F1/C1): check_ready_slice.py passed at pre-flight — the slice is ready and its hub
resolves; an unready slice halted (REC1).
SE-2 (F3/C3): lint_grounding.py exits 0 — quality.md conforms to the Quality lens template
(Intent, Gates), no missing/extra/empty section.
SE-3 (F4/C4): the content-quality eval gate (grounding_gate.py) passes — quality.md is
self-explaining and clears the stranger test.
SE-4 (F5/C5): validate_quality.py — every gate grounds in a profile NFR gate that applies or a
functionality rule; any material choice names a decision that resolves.
SE-5 (F6/C6): validate_quality.py — the gates consider every functionality the slice bundles
(coverage).
SE-6 (F7/C7): validate_quality.py — the gates ground on no other realize lens.
SE-7 (F8/C8): every gate is a checkable bar — the Gates table carries a bar and a check; a bare
adjective with no value/standard/check fails the content eval and the linter's substance floor.
On any GAP, apply the matching recovery (REC3–REC8) and re-run before the checkpoint.
Phase: Checkpoint
Step 3 — Human review (conditional gate, class: standard) · Owner: play · Depends on: Step 2
This is the single checkpoint (C10) — the agent never skips it on its own judgment. It is a
conditional gate per standards/rules/gate-config.md (#467 — /quality is one of the eleven
conditional document plays). Resolve, first match wins: pinned (n/a here) → gates.plays.quality →
the learned policy → gates.classes.standard → gates.default (absent ⇒ on). When config resolves
it off, record gate skipped by config (<resolution path>) as a Checkpoint Decisions row in the
evidence and proceed on the validated draft.
For the policy leg, classify the draft-vs-live change shape mechanically:
python3 scripts/classify_change.py --play quality --draft <working>/draft --live <product_base> --out <working>/shape.json
Look the shape key up in the config-resolved learned policy (gates.conditional.policy →
gate-policy.yaml). Shape in auto: AND not in never_auto: AND no blocking finding (a Step 2
lint gap or content-eval fail) → auto-pass: record gate auto-passed by learned policy (shape: <shape-key>, policy v<version>) as a Checkpoint Decisions row plus the draft's diff summary
(the axis counts from shape.json), append the ledger line, and proceed — no wait:
python3 scripts/gate_eval.py append --ledger <gates.conditional.ledger> --play quality \
--issue <issue> --shape <shape-key> --predicted auto --human auto_pass \
--ts <run ts> --policy-version <policy version>
Anything else → gate: render the approval prompt — the proposed intent and the gates inline,
plus any decision — and wait for the typed response. Approve → persist; cancel → halt, nothing
written. Then append the ledger line with the human's real action:
python3 scripts/gate_eval.py append --ledger <gates.conditional.ledger> --play quality \
--issue <issue> --shape <shape-key> --predicted gate \
--human approved_clean|approved_edited|rejected --ts <run ts>
<run ts> is the run's own timestamp, derived the same way the close derives ts (date -u) and
passed by the orchestrator — the script never reads the wall clock. EVERY crossing appends exactly
one live-eval ledger line, gated or auto.
SE-9 (F10/C10): the lens is persisted only after this gate resolves — a typed approval, a
recorded config skip, or a recorded policy auto-pass; Step 4 is the sole writer and depends on this
step.
SE-11 (F12/C10): every conditional-gate crossing appended exactly one live-eval ledger line
(gate_eval.py append), and an auto-pass fired only for a shape the policy lists in auto: (and not
in never_auto:) with no blocking finding.
Phase: Apply
Step 4 — Persist · Owner: play · Depends on: Step 3
First snapshot the live spine and the slice folder so Step 5 can verify (cp the spine to
<working>/spine-before.yaml; cp -R the slice folder to <working>/slice-before). Then persist on
the fixed allowlist — only this slice's quality.md + quality-gates.yaml (re-derive) and decisions
(skip-if-exists):
python3 scripts/apply_quality.py --draft <working>/draft --product-base <product_base> --out-manifest <working>/apply-manifest.json
The apply manifest carries the machine applied fields the close's stop-condition gate reads (#464):
lens_applied: true (quality.md landed) and gates_machine_applied: true (the machine sibling
landed).
Step 5 — Verify persisted · Owner: play · Depends on: Step 4
Verify the persist was surgical:
python3 scripts/check_quality.py --cap-before <working>/slice-before --cap-dir <product_base>/product-os/<domain>/slices/<slice> --spine-before <working>/spine-before.yaml --spine-after <product_base>/product-os/_spine.yaml
SE-8 (F2/F9/C2/C9): the only files changed in the slice folder are lens/quality.md and its
machine sibling lens/quality-gates.yaml (decisions may be added, never edited in place); the spine
— and with it the profile, the slice record, and the other lenses — is byte-identical. Nothing
outside the allowlist was written.
SE-10 (F11/C11): the close is stop-condition gated — check_stop_condition.py over the baked
stop-condition.yaml (D1–D4: draft lens, grounding manifest, lens_applied,
gates_machine_applied) reads held before the run may close COMPLETED; anything else closes
HALTED with the unmet clauses named (REC11).
Phase: Scenario Validation
Step 6 — Scenario evals · Owner: play · Depends on: Step 5
- SCE-1 (S1 — quality engineer):
quality.md is a valid Quality Lens doc clearing the linter +
the content eval, and the spine/slice/profile/other lenses are byte-identical.
- SCE-2 (S2 — product owner, grounded gates): every gate traces to a profile NFR gate that
applies or a functionality rule; material choices name a decision that resolves.
- SCE-3 (S3 — reviewer, concrete): every gate is a checkable bar — a value or named standard plus
a check — never a bare adjective.
- SCE-4 (S4 — architect, hub-only): no other realize lens was read or written.
- SCE-5 (S5 — product owner, re-run): a re-run re-derives only
quality.md; everything else
byte-identical; no accepted decision edited in place.
- SCE-6 (S6 — reviewer): the checkpoint showed the intent and the gates inline, and no
product-model file was written before approval — or, on the auto-pass path, the shape was
policy-listed and the recorded auto-pass, the ledger line, and the diff summary stood in for the
wait (nothing written before the gate resolved).
Phase: Evidence & Close
Step 7 — Close · Owner: play · Depends on: Step 6
Run the Standard Play Close. /quality is a slice-realize play — record evidence per the D1 rule.
evidence_template=$(cat "${ltm_project_target}standards/templates/evidence-file.md")
delivery_template=$(cat "${ltm_project_target}standards/templates/delivery-report.md")
ts=$(date -u +%Y%m%d-%H%M%S)
evidence_dest="${evidence_base}${ts}.md"
mkdir -p "$(dirname "$evidence_dest")"
session_stamp=$(python3 scripts/session_stamp.py --phase close \
--marker "${stm_base}_realize/quality/status/session-stamp-quality.json")
python3 scripts/check_stop_condition.py \
--manifest "<play-dir>/stop-condition.yaml" \
--base "${stm_base}_realize/quality/" \
--out "${stm_base}_realize/quality/status/stop-condition-quality.yaml"
sc_exit=$?
python3 scripts/distill_gate_policy.py --ledger "${gates_ledger}" --policy "${gates_policy}" \
--streak "${gates_streak}" --project "${project_name}" || true
Step C0 — bind the verdict. sc_exit == 0 (held) permits status: COMPLETED.
Anything else closes HALTED with exit_reason: stop_condition_unmet and the evidence's
Stop Condition section names every unmet clause. An unevaluable verdict is never a pass.
/quality runs on the slice-realize issue /arch opened, so it is project-scoped:
evidence_base="${stm_base}${issue}/evidence/quality/" and slug="#${issue}".
Step C1 — Write evidence file. Gated by the resolved evidence.record flag. When false, skip and
record evidence skipped (record=false). Otherwise fill the evidence-file.md slots (play quality,
run_id quality-${ts}, slice slug, started/completed, status per C0, exit_reason; artifacts: the
slice's quality.md, its machine sibling quality-gates.yaml, the manifest, any decision, the
stop-condition verdict; the content-eval verdict; step + scenario evals SE-1…SE-11 / SCE-1…SCE-6;
checkpoint decision (incl. any gate skipped by config or gate auto-passed by learned policy row,
with the diff summary and the ledger line); the session identity stamp fields from
$session_stamp (#463): session_id, ledger_file, ledger_start_offset, ledger_end_offset (null when
unresolved — never blocks the close); and stop_condition per C0 with the Stop Condition section
filled) and write to $evidence_dest. Do NOT hand-author the body.
Step C2 — Render delivery report. Also render the Next line: resolve this play in standards/rules/pipeline-next.md and emit **Next:** /<command> — <why>. Or run /next to see all recommended actions. (only /next pointer, or omit, when the mapped command is null), per play-close.md. Fill the delivery-report.md slots: ## quality Delivered — ${slug}, the Run Summary table (incl. the stop-condition verdict), the Pipeline Steps table, the
Artifacts Produced table (the quality lens + its machine sibling quality-gates.yaml + any
decision), Next Steps (run /run to close the non-functional pipe), and a pointer to
$evidence_dest. Always emitted.
Scenario Validation
| Scenario | Persona | Eval |
|---|
| S1 — first run | quality engineer | SCE-1 |
| S2 — grounded gates | product owner | SCE-2 |
| S3 — concrete | reviewer | SCE-3 |
| S4 — hub-only | architect | SCE-4 |
| S5 — re-run | product owner | SCE-5 |
| S6 — the checkpoint | reviewer | SCE-6 |
Recovery
| For | Trigger | Direction | Handoff |
|---|
| F1 | the slice is absent, a functionality does not resolve, or the profile is not firmed | halt and route to /shape or /understand before /quality runs | human |
| F2 | a write touched something beyond this slice's quality.md, its machine sibling quality-gates.yaml, or a decision | revert the out-of-scope write; /quality writes only the slice's quality.md, quality-gates.yaml, and any decision | autonomous |
| F3 | quality.md fails the template/shape or carries out-of-scope content | re-emit to the Quality lens template (intent and gates only) | autonomous |
| F4 | quality.md fails the content-quality eval | rewrite the failing section to the judge's cited fixes and re-judge until the gate passes | autonomous |
| F5 | an invented gate, or a material choice with no decision | re-tie each gate to a profile gate or a functionality rule, and record the material decision | autonomous |
| F6 | a functionality was not considered | extend the gates to cover the missing functionality's quality-relevant rules | autonomous |
| F7 | /quality read or depended on another lens | remove the dependency; /quality derives only from the slice's hub | autonomous |
| F8 | a gate is not checkable — a vague adjective with no value, standard, or check | re-draft the gate as a value or named standard plus how it is checked | autonomous |
| F9 | a non-lens/non-decision file changed, or an accepted decision was edited in place | restore it and re-apply only quality.md + quality-gates.yaml and the new decision, after a human confirms the restore | human |
| F10 | the lens was persisted before the checkpoint gate resolved | revert the premature write and re-present the checkpoint; persist only after the gate resolves (a typed approval, a recorded config skip, or a recorded policy auto-pass) | human |
| F11 | the run is about to close COMPLETED with the Done means unmet | produce the missing artifact — re-run the failed step, or re-run apply_quality.py so the apply manifest carries the machine fields — then re-evaluate the stop condition; the close stays HALTED until the verdict reads held | autonomous |
| F12 | a conditional-gate crossing left no live-eval ledger line, or an auto-pass fired for a shape the policy does not list as auto (or that carried a blocking finding) | re-append the missing ledger line from the recorded crossing; when the auto-pass was unearned, re-run the gate as a live wait (render the prompt, take the typed verdict) and append the corrected line | autonomous |
Pause and Resume
Steps run top to bottom. On entry, resolve config, resolve the target slice, check the status marker,
skip completed steps, reset any in-progress step to pending, and continue.
Compilation Metadata
| Field | Value |
|---|
| fingerprint | sha256:fe14702689bf1ee30ee35218308515a36b206aefbc968934bd0ef8c15a9b6221 (of reference/ice.md) |
| compiled_by | play-editor (#466 Batch C; #467 Batch B — conditional learned gate) |
| pipeline_position | none |
| position_exception | middle of the non-functional realize pipe — runs on the branch /arch started; the close belongs to /run |
| workflow_structure | A (single checkpoint — conditional learned gate, class: standard, per gate-config.md #467; gated close) |
| stop_condition | stop-condition.yaml (D1–D4), gate live at Step C0 |
| domain_agents | 1 (product-os-keeper) |
| utility_agents | 0 |
| skills_used | author-quality-lens |
| scripts | 12 (preflight, check_ready_slice, lint_grounding, grounding_gate, validate_quality, apply_quality, check_quality, check_stop_condition — Done-means gate, session_stamp — #463 identity stamp, classify_change + gate_eval + distill_gate_policy — #467 conditional gate) |
| step_evals | 11 (SE-1…SE-11) |
| scenario_evals | 6 (SCE-1…SCE-6) |
| recovery_entries | 12 (one per failure condition; 9 autonomous / 3 human) |