> ## Documentation Index
> Fetch the complete documentation index at: https://docs.plannotator.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Software Factory Control Packet Template and Example

> Copy six Markdown files for intent, context, plan, review, evidence, and decisions in an agent-native software delivery workflow.

Use this six-file Markdown packet to keep a substantial software change connected from intent through evidence and a shipping decision. It is designed for work that spans agents, people, sessions, interfaces, data, or rollout steps.

```text theme={null}
software-factory-control-packet/
├── 01-intent.md
├── 02-context.md
├── 03-plan.md
├── 04-review-rubric.md
├── 05-evidence.md
└── 06-decision-log.md
```

Each file has one job:

| File                  | Job                                                                                          |
| --------------------- | -------------------------------------------------------------------------------------------- |
| `01-intent.md`        | Define the user problem, desired result, scope, constraints, owner, and acceptance criteria. |
| `02-context.md`       | Select source links, code paths, ADRs, examples, conflicts, and freshness notes.             |
| `03-plan.md`          | Order the changes, dependencies, risks, verification steps, and stop conditions.             |
| `04-review-rubric.md` | Apply risk-based checks for intent, correctness, security, operability, and maintainability. |
| `05-evidence.md`      | Preserve test receipts, screenshots, benchmarks, deploy proof, and unresolved failures.      |
| `06-decision-log.md`  | Record choices, rejected alternatives, rationale, author, date, and supersession state.      |

Do not fill every placeholder for a small change. Use the complete packet when losing the reasoning, proof, or decision trail would create more risk than maintaining six short files. See [What is an AI software factory?](/learn/ai-development/what-is-an-ai-software-factory) for the operating model around the packet.

*Published and last reviewed July 27, 2026. Written and maintained by the Plannotator documentation team.*

## Blank copyable packet

Create the directory and copy each block into the named file.

### `01-intent.md`

```md theme={null}
# [Change name]: intent

Status: Draft | Accepted | Superseded
Owner: [Person or team accountable for the result]
Created: [YYYY-MM-DD]
Last reviewed: [YYYY-MM-DD]
Source signal: [Issue, incident, interview, metric, obligation, or request]

## User problem

[Who is affected, what they cannot do or what goes wrong, and the evidence
that establishes the problem.]

## Desired result

[Observable user or system outcome. Describe the result, not the implementation.]

## Scope

### In scope

- [Included behavior, user, interface, system, or migration]

### Out of scope

- [Explicitly excluded behavior or follow-up]

## Constraints

- [Security, privacy, compatibility, cost, performance, legal, schedule, or
  platform boundary]

## Acceptance criteria

| ID | Observable criterion | Evidence required |
| --- | --- | --- |
| AC-1 | [Behavior that can be accepted or rejected] | [Test, screenshot, benchmark, receipt, or decision] |
| AC-2 | [Behavior that can be accepted or rejected] | [Evidence] |

## Decision rights

- Intent owner: [Who can change scope or acceptance criteria]
- Technical owner: [Who can accept implementation tradeoffs]
- Release owner: [Who can ship, stage, hold, or roll back]

## Open questions

- [Question, owner, and date needed]
```

### `02-context.md`

```md theme={null}
# [Change name]: context

Status: Draft | Verified | Stale
Context owner: [Person or team]
Last verified: [YYYY-MM-DD]
Refresh trigger: [Event that requires this file to be checked again]

## Source precedence

When sources conflict, use this order:

1. [Current contract, test, or production behavior]
2. [Accepted ADR or maintained specification]
3. [Current implementation]
4. [Plans, issues, examples, or historical notes]

Escalate rather than guessing when a higher-priority source conflicts with the
accepted intent.

## Source links

| Source | Why it matters | Verified | Freshness or caveat |
| --- | --- | --- | --- |
| [URL or repository path] | [Relevant fact or boundary] | [YYYY-MM-DD] | [Known limitation] |

## Code and data paths

| Path or interface | Responsibility | Owner |
| --- | --- | --- |
| `[path, route, schema, event, or command]` | [What it controls] | [Team] |

## Accepted decisions

- [ADR or decision link]: [Constraint imposed on this change]

## Representative examples

- Good: [Fixture, trace, screenshot, or prior change]
- Failure: [Incident, rejected output, or counterexample]

## Conflicts and uncertainties

| ID | Conflict or uncertainty | Resolution owner | Status |
| --- | --- | --- | --- |
| C-1 | [What does not agree or is unknown] | [Owner] | Open | Resolved |

## Sensitive material

- [Credentials, customer data, regulated data, or private source that agents
  must not copy into outputs]
```

### `03-plan.md`

```md theme={null}
# [Change name]: plan

Status: Draft | Accepted | In progress | Complete | Stopped
Plan owner: [Person or agent]
Approved by: [Decision owner, if required]
Last revised: [YYYY-MM-DD]
Intent version: [Commit, version, or last-reviewed date for 01-intent.md]
Context version: [Commit, version, or last-verified date for 02-context.md]

## Approach

[Two or three sentences describing the smallest viable implementation and its
important boundaries.]

## Ordered changes

| Step | Change | Depends on | Supports | Verification |
| --- | --- | --- | --- | --- |
| P-1 | [Bounded implementation step] | [Step or source] | [AC IDs] | [Evidence ID or command] |
| P-2 | [Bounded implementation step] | [Step] | [AC IDs] | [Verification] |

## Interfaces and migrations

- API or event changes: [Routes, schemas, compatibility]
- Data changes: [Migration, backfill, idempotency, rollback]
- UI changes: [States, errors, accessibility, responsive behavior]
- Operations: [Flags, observability, rollout, recovery]

## Risks

| ID | Risk | Likelihood | Impact | Control | Owner |
| --- | --- | --- | --- | --- | --- |
| R-1 | [Failure or misuse] | [Low / Medium / High] | [Low / Medium / High] | [Prevention, detection, recovery] | [Owner] |

## Verification plan

- Deterministic checks: [Build, types, tests, contracts, policy]
- Scenario checks: [End-to-end behavior and failure cases]
- Visual checks: [Desktop, mobile, light/dark, accessibility]
- Operational checks: [Benchmark, migration, deploy, rollback, recovery]
- Independent review: [What needs judgment, by whom, and why]

## Stop conditions

Stop execution and return evidence if:

- [Security, data-integrity, scope, cost, or repeated-failure threshold]
- A source conflict changes the accepted intent.
- Required evidence cannot be produced without broader authority.

## Rollout and recovery

1. [First cohort or environment]
2. [Gate and evidence before expansion]
3. [Next cohort]

Kill switch: [Owner and action]
Rollback or recovery: [Procedure and data consequence]
```

### `04-review-rubric.md`

```md theme={null}
# [Change name]: review rubric

Status: Draft | Accepted | Complete
Rubric owner: [Person or team]
Last reviewed: [YYYY-MM-DD]

## Rating scale

- Pass: evidence supports the criterion.
- Revise: bounded correction or missing evidence is required.
- Block: material risk, intent conflict, or failed hard gate prevents shipping.
- Not applicable: reviewer states why the dimension does not apply.

A Pass rating cannot override a failed required check.

## Review

| Dimension | Risk-based questions | Required evidence | Rating | Reason |
| --- | --- | --- | --- | --- |
| Intent | Does the result solve the accepted problem without expanding scope? | Intent criteria mapped to evidence | [Rating] | [Source-backed reason] |
| Correctness | Are success, failure, retry, concurrency, and data-integrity behaviors correct? | Tests, scenarios, data receipts | [Rating] | [Reason] |
| Security | Are identity, authorization, secrets, sensitive data, and abuse boundaries correct? | Threat review and negative tests | [Rating] | [Reason] |
| Operability | Can operators observe, stop, roll back, and recover the change? | Telemetry, rollout, rollback, recovery proof | [Rating] | [Reason] |
| Maintainability | Are ownership, interfaces, tests, and decisions understandable after this task? | Diff, docs, contracts, decision links | [Rating] | [Reason] |

## Hard gates

- [ ] Required build, type, test, and contract checks pass.
- [ ] No unresolved blocker in `02-context.md`.
- [ ] Every acceptance criterion maps to evidence or an explicit unresolved result.
- [ ] Required security and data-integrity checks pass.
- [ ] Rollback or recovery evidence meets the release stage.

## Findings

| ID | Severity | Finding | Evidence | Owner | Resolution |
| --- | --- | --- | --- | --- | --- |
| F-1 | [Blocker / High / Medium / Low] | [Finding] | [Link or receipt] | [Owner] | [Open / Fixed / Accepted] |

## Recommendation

Release | Stage | Revise | Reject | Hold

[State the decision this evidence supports and what it does not support.]
```

### `05-evidence.md`

```md theme={null}
# [Change name]: evidence

Status: Collecting | Ready for decision | Incomplete | Superseded
Evidence owner: [Person or agent]
Revision proved: [Commit, artifact digest, build, or release]
Environment: [Exact environment]
Collected: [YYYY-MM-DD]

## Acceptance-criteria coverage

| Criterion | Evidence | Result | Remaining uncertainty |
| --- | --- | --- | --- |
| AC-1 | E-1 | Pass | [None or uncertainty] |
| AC-2 | E-2 | Fail | Unresolved | [What remains] |

## Receipts

### E-1: [Evidence name]

- Supports: [AC IDs, plan steps, rubric dimensions]
- Revision: [Commit or artifact digest]
- Environment and data: [Where and with what fixture]
- Command or procedure: `[Exact command or steps]`
- Result: Pass | Fail | Partial
- Receipt: [Attached log, screenshot, report, trace, or URL]
- Notes: [Limits, flakes, exclusions, or interpretation]

### E-2: [Evidence name]

- Supports: [IDs]
- Revision: [Revision]
- Environment and data: [Details]
- Command or procedure: `[Command or steps]`
- Result: Pass | Fail | Partial
- Receipt: [Artifact]
- Notes: [Limits]

## Visual and interaction evidence

| View or flow | Evidence | Result | Notes |
| --- | --- | --- | --- |
| [Desktop, mobile, error, empty, keyboard, screen reader] | [Screenshot, video, or notes] | [Result] | [Caveat] |

## Performance and operational evidence

| Check | Dataset or load | Threshold | Result | Receipt |
| --- | --- | --- | --- | --- |
| [Benchmark, migration, rollout, rollback, recovery] | [Fixed input] | [Accepted limit] | [Measured result] | [Link] |

## Deploy or release proof

- Release stage: [Environment or cohort]
- Artifact: [Digest or version]
- Deployed by: [Actor]
- Started: [Timestamp]
- Observed through: [Timestamp]
- Health and guardrails: [Result and receipt]
- Rollback or kill switch: [Status and receipt]

## Unresolved failures

| ID | Related criteria | Failure or missing proof | Consequence | Owner | Next decision |
| --- | --- | --- | --- | --- | --- |
| U-1 | [AC IDs] | [Exact failure or missing receipt] | [What cannot be claimed or shipped] | [Owner] | [Action and date] |
```

### `06-decision-log.md`

```md theme={null}
# [Change name]: decision log

Status: Active
Log owner: [Person or team]
Last updated: [YYYY-MM-DD]

## Decisions

### D-1: [Decision title]

- Status: Proposed | Accepted | Rejected | Superseded
- Date: [YYYY-MM-DD]
- Author: [Person or accountable team]
- Decision: [What was chosen]
- Rationale: [Why, tied to intent, context, risk, and evidence]
- Evidence reviewed: [AC, E, F, ADR, issue, or source IDs]
- Alternatives rejected:
  - [Alternative]: [Reason rejected]
- Consequences:
  - [Positive, negative, follow-up, or constraint]
- Supersedes: [Decision ID or none]
- Superseded by: [Decision ID or none]

### D-2: [Shipping decision]

- Status: Accepted
- Date: [YYYY-MM-DD]
- Author: [Release owner]
- Decision: Release | Stage | Revise | Reject | Hold [scope]
- Rationale: [Evidence and unresolved risk]
- Evidence reviewed: [IDs]
- Conditions:
  - [Gate before the next stage]
- Alternatives rejected:
  - [Alternative]: [Reason]
- Supersedes: [ID or none]
- Superseded by: [ID or none]
```

## Keep the packet connected

Use stable IDs so readers can trace a decision without guessing:

```text theme={null}
signal → AC-3 → P-4 → R-2 → E-7 → F-1 → D-3
```

* An acceptance criterion should map to one or more plan steps and evidence receipts.
* A plan step should name the criteria it supports and how it will be verified.
* A rubric finding should link to the exact evidence or missing proof.
* A shipping decision should state which criteria and unresolved results it accepts.
* A changed criterion should invalidate or refresh downstream plans and evidence.

Do not silently rewrite a completed receipt or accepted decision. Add a new receipt or decision and mark the old record superseded.

## Completed fictional example: Quay Billing

Everything in this example is fictional, including Quay Billing, its product, people, code paths, metrics, datasets, results, dates, and identifiers. The example does not describe a Plannotator customer or a Plannotator product capability.

The fictional change adds a resumable CSV price-adjustment import to a subscription-billing product. It is deliberately substantial enough to justify the packet: browser UI, API and durable data, financial and tenant-isolation risk, failure injection, accessibility, performance, and staged rollout.

### Completed `01-intent.md`

```md theme={null}
# Resumable bulk price-adjustment import: intent

Status: Accepted
Owner: Maya Chen, fictional Billing Operations product lead
Created: 2026-07-08
Last reviewed: 2026-07-14
Source signal: Fictional QB-421 support-pattern report and QB-77 operations incident

## User problem

Billing administrators at fictional Quay Billing can edit prices one subscription
at a time. Large annual price changes require repeated manual work. A failed
browser session gives the administrator no reliable record of which adjustments
were applied. The fictional QB-421 report groups 14 support cases that describe
this problem. The fictional QB-77 incident records one partial manual update.

## Desired result

A billing administrator can upload, validate, preview, and confirm a large CSV
price adjustment as one resumable operation. The system either records each valid
adjustment exactly once or returns an explicit unresolved result. Operators can
stage, stop, and recover the feature.

## Scope

### In scope

- CSV upload for same-tenant billing administrators.
- Validation and preview before any billing write.
- Row-level rejection reasons and a rejected-row export.
- Resumable background validation and apply jobs.
- Exactly-once adjustment effect under retry and worker restart.
- Start, confirm, cancel, and completion audit events.
- Progress, pre-commit cancellation, and defined accessibility checks.
- A 5%, 25%, and 100% staged rollout with a kill switch.

### Out of scope

- Creating new subscriptions or products.
- Cross-tenant imports.
- Scheduling an import for a future date.
- Editing a confirmed import in place.
- Automatic currency conversion.
- A public import API.

## Constraints

- Existing ledger entries are immutable.
- Prices are stored as integer minor units with an ISO currency code.
- A confirmed import cannot mix currencies for one subscription.
- Upload bytes expire after seven days; durable audit and result records remain.
- No rollout may advance after a data-integrity or tenant-isolation failure.
- The first release uses the existing fictional Postgres job store and object
  storage. Introducing another queue or database is out of scope.

## Acceptance criteria

| ID | Observable criterion | Evidence required |
| --- | --- | --- |
| AC-1 | An admin can preview a CSV with up to 100,000 rows or 50 MB, see row-level errors, and make no billing changes. | Preview integration suite, fixed-dataset receipt, and database snapshot |
| AC-2 | Confirming a valid preview applies each adjustment exactly once across retries and worker restarts. | Fault-injection suite and unique-ledger receipt |
| AC-3 | Only a same-tenant billing admin can start, confirm, cancel, or read an import; start, confirm, cancel, and completion events are audited. | Authorization matrix and audit-event assertions |
| AC-4 | The UI reports progress, supports cancellation before commit, exports rejected rows, and passes the packet's keyboard and screen-reader checks. | Desktop/mobile captures, keyboard script, screen-reader notes, and export assertion |
| AC-5 | On dataset DS-100K in fictional staging, preview p95 is below 90 seconds and apply p95 is below five minutes. | Versioned benchmark report with 20 runs per operation |
| AC-6 | The feature can roll out at 5%, 25%, and 100% with a kill switch; database-failover recovery is proved before 100%. | Cohort receipts, kill-switch test, and failover rehearsal |

## Decision rights

- Intent owner: Maya Chen may change scope or acceptance criteria.
- Technical owner: Rafael Ortiz, fictional Billing Platform lead, may accept
  implementation tradeoffs that do not change intent.
- Release owner: Priya Nair, fictional on-call engineering manager, may stage,
  hold, or roll back the release.

## Open questions

- None block implementation. One release-stage requirement remains: AC-6 requires
  a passing failover rehearsal before the 100% cohort.
```

### Completed `02-context.md`

```md theme={null}
# Resumable bulk price-adjustment import: context

Status: Verified
Context owner: Rafael Ortiz, fictional Billing Platform lead
Last verified: 2026-07-14
Refresh trigger: A change to ledger write semantics, admin authorization, job
leases, upload retention, or the accepted intent

## Source precedence

When sources conflict, use this order:

1. Current billing-ledger constraints and authorization tests.
2. Accepted ADRs QB-ADR-12, QB-ADR-19, and QB-ADR-27.
3. Current implementation at fictional commit `7c91b2e`.
4. QB-421, QB-77, prototypes, and historical plans.

Escalate to the intent and technical owners if a higher-priority source conflicts
with the accepted result.

## Source links

| Source | Why it matters | Verified | Freshness or caveat |
| --- | --- | --- | --- |
| `issues/QB-421.md` | Groups 14 fictional support cases about bulk price changes | 2026-07-14 | Support sample, not usage telemetry |
| `incidents/QB-77.md` | Describes one fictional partial manual adjustment | 2026-07-14 | Manual workflow, not an import failure |
| `adr/QB-ADR-12-immutable-ledger.md` | Forbids in-place ledger mutation | 2026-07-14 | Accepted |
| `adr/QB-ADR-19-tenant-authorization.md` | Requires tenant membership plus billing-admin role | 2026-07-14 | Accepted |
| `adr/QB-ADR-27-job-leases.md` | Defines lease, retry, and restart behavior | 2026-07-14 | Accepted |
| `fixtures/imports/DS-100K.csv.sha256` | Pins the fictional performance dataset | 2026-07-14 | Synthetic data only |
| `prototypes/import-preview.html` | Shows the accepted interaction sequence | 2026-07-14 | Visual behavior only; not an API contract |

## Code and data paths

| Path or interface | Responsibility | Owner |
| --- | --- | --- |
| `apps/admin/src/routes/price-imports/` | Import list, upload, preview, progress, and result UI | Admin Experience |
| `services/billing/src/http/price-imports.ts` | Tenant-scoped import routes | Billing Platform |
| `services/billing/src/jobs/price-import-worker.ts` | Validation and apply job states | Billing Platform |
| `packages/auth/src/require-billing-admin.ts` | Same-tenant billing-admin authorization | Identity |
| `db/schema/price_imports.sql` | Import, row-result, and apply-ledger records | Billing Platform |
| `events/billing-import.schema.json` | Audit event contract | Security Platform |
| `ops/flags/price-import.yaml` | Cohort and kill-switch configuration | Reliability |

## Accepted decisions

- QB-ADR-12: Write compensating ledger entries; never edit or delete accepted
  ledger rows.
- QB-ADR-19: Route handlers must derive tenant identity from the authenticated
  session, never from an untrusted body field.
- QB-ADR-27: A worker may resume an expired lease, so every apply operation must
  be idempotent.

## Representative examples

- Good: `fixtures/imports/valid-mixed-adjustments.csv` contains increases,
  decreases, unchanged rows, and a deterministic ordering.
- Failure: `fixtures/imports/duplicate-external-id.csv` repeats one external row
  identifier and must produce one accepted row plus one rejection.
- Failure: QB-77 shows why partial progress without a durable result is unsafe.

## Conflicts and uncertainties

| ID | Conflict or uncertainty | Resolution owner | Status |
| --- | --- | --- | --- |
| C-1 | The prototype says Cancel while the job-state enum says Abort. | Maya Chen | Resolved: UI says Cancel; API and event use `canceled` |
| C-2 | The old plan proposes a new queue, but the accepted intent excludes it. | Rafael Ortiz | Resolved: use the current job store |
| C-3 | Failover behavior has unit coverage but no environment receipt. | Priya Nair | Open for 100% rollout; does not block implementation or 25% |

## Sensitive material

- Production billing records, customer names, invoice data, access tokens, and
  uploaded customer CSV files must not enter prompts, fixtures, screenshots, or
  benchmark output.
- DS-100K is synthetic and contains no customer data.
```

### Completed `03-plan.md`

```md theme={null}
# Resumable bulk price-adjustment import: plan

Status: Complete
Plan owner: Aster, fictional coding agent, with Rafael Ortiz accountable
Approved by: Rafael Ortiz on 2026-07-15
Last revised: 2026-07-21
Intent version: `01-intent.md` reviewed 2026-07-14
Context version: `02-context.md` verified 2026-07-14

## Approach

Add an immutable import record with resumable validation and apply jobs. Preview
stores row results but never writes the billing ledger. Confirmation creates one
apply-ledger key per valid source row, so a retried worker can resume without
duplicating the financial effect. Reuse the current job store, object storage,
authorization predicate, audit stream, and feature-flag service.

## Ordered changes

| Step | Change | Depends on | Supports | Verification |
| --- | --- | --- | --- | --- |
| P-1 | Add import, row-result, and apply-ledger schemas with unique `(import_id, source_row_id)` | QB-ADR-12, QB-ADR-27 | AC-1, AC-2 | E-1, E-2 |
| P-2 | Add upload and validation job; reject files over 100,000 rows or 50 MB before enqueue | P-1 | AC-1, AC-5 | E-1, E-5 |
| P-3 | Add tenant-scoped preview and rejected-row export routes | P-1, P-2, QB-ADR-19 | AC-1, AC-3, AC-4 | E-1, E-3, E-4 |
| P-4 | Add idempotent confirmation and resumable apply worker | P-1, P-2 | AC-2, AC-3 | E-2, E-3 |
| P-5 | Emit start, confirm, cancel, and completion audit events | P-2, P-4 | AC-3 | E-3 |
| P-6 | Build upload, preview, progress, cancel, result, and error UI states | P-3, P-4 | AC-4 | E-4 |
| P-7 | Add cohort flag, kill switch, dashboards, and rollout runbook | P-2 through P-6 | AC-5, AC-6 | E-5, E-6 |
| P-8 | Run fixed-dataset, retry, restart, accessibility, cohort, and failover checks | P-1 through P-7 | AC-1 through AC-6 | E-1 through E-6 |

## Interfaces and migrations

- API:
  - `POST /v1/price-imports` accepts metadata and a signed upload reference.
  - `GET /v1/price-imports/{id}` returns state and counts.
  - `GET /v1/price-imports/{id}/rows?status=rejected` returns paged row results.
  - `POST /v1/price-imports/{id}/confirm` starts apply from a completed preview.
  - `POST /v1/price-imports/{id}/cancel` cancels only before commit begins.
- Data:
  - Add `price_imports`, `price_import_rows`, and
    `price_import_apply_ledger`.
  - Deploy additive schema before code. No backfill.
  - Rollback disables new imports and lets started jobs finish or enter an
    explicit failed state. Accepted ledger entries remain immutable.
- UI:
  - Upload, validating, preview, confirmation, applying, canceled, failed, and
    completed states.
  - Progress is exposed as text and a semantic progress element.
  - The primary action retains keyboard focus after state changes.
  - Rejected rows are available as a CSV download.
- Operations:
  - Cohort flag by tenant ID, emergency global disable, job-age and failure
    dashboards, duplicate-key counter, and audit-event count.

## Risks

| ID | Risk | Likelihood | Impact | Control | Owner |
| --- | --- | --- | --- | --- | --- |
| R-1 | Retry applies one price adjustment twice | Medium | High | Unique apply-ledger key, transaction boundary, fault-injection test | Billing Platform |
| R-2 | One tenant reads or controls another tenant's import | Low | High | Session-derived tenant predicate on every route plus negative matrix | Identity |
| R-3 | Cancel races with commit and leaves a partial result | Medium | High | State transition lock; cancel refused after `applying` starts | Billing Platform |
| R-4 | Large parse starves request workers | Medium | Medium | Object-store stream and background validation job | Reliability |
| R-5 | Progress and errors are inaccessible | Medium | Medium | Semantic status, focus checks, keyboard script, screen-reader review | Admin Experience |
| R-6 | Failover resumes from an unsafe boundary | Low | High | Lease recovery design and environment rehearsal before 100% | Reliability |

## Verification plan

- Deterministic checks:
  - schema migration up/down rehearsal in an empty and populated fixture;
  - type, unit, route-contract, and integration suites;
  - authorization matrix for role, tenant, and import state;
  - unique-ledger and audit-event assertions.
- Scenario checks:
  - valid, invalid, duplicate-ID, mixed-currency, oversize, retry, restart,
    cancellation, and expired-upload cases;
  - preview leaves billing data unchanged;
  - confirm produces one durable effect per valid row.
- Visual checks:
  - upload, preview, progress, failed, canceled, and complete at 1440 by 900 and
    390 by 844;
  - keyboard-only task sequence;
  - VoiceOver headings, status announcements, errors, and progress.
- Operational checks:
  - 20 preview and 20 apply runs with DS-100K;
  - 5% and 25% cohort observation;
  - kill-switch exercise;
  - database-failover rehearsal before 100%.
- Independent review:
  - Identity reviews R-2.
  - Reliability reviews R-4 and R-6.
  - Maya Chen judges interaction and rejected-row usability.
  - Priya Nair makes each rollout decision.

## Stop conditions

Stop execution or rollout and return evidence if:

- any retry or restart produces a duplicate ledger effect;
- any non-admin or cross-tenant request returns import data or changes state;
- cancellation produces a partial commit;
- the fixed benchmark exceeds its threshold twice in succession;
- a schema or current-contract conflict changes accepted intent;
- the duplicate-key, job-failure, or billing-error guardrail crosses its runbook
  threshold.

## Rollout and recovery

1. Enable for fictional internal tenants, then 5% of eligible tenants.
2. Observe 24 hours and require E-6 cohort and kill-switch receipts.
3. Enable 25% and observe 48 hours.
4. Run the database-failover rehearsal.
5. Enable 100% only after E-6 proves recovery and Priya Nair records a new
   decision.

Kill switch: Reliability disables `price_import.enabled` globally. Existing
applying jobs may finish; queued or validating jobs move to a resumable held state.

Recovery: Restart workers after the job-store lease expires. Resume from row
results and apply-ledger keys. Never delete or rewrite accepted billing ledger
entries.
```

### Completed `04-review-rubric.md`

```md theme={null}
# Resumable bulk price-adjustment import: review rubric

Status: Complete for 25% rollout
Rubric owner: Rafael Ortiz
Last reviewed: 2026-07-26

## Rating scale

- Pass: evidence supports the criterion.
- Revise: bounded correction or missing evidence is required.
- Block: material risk, intent conflict, or failed hard gate prevents the
  proposed release stage.
- Not applicable: reviewer states why the dimension does not apply.

A Pass rating cannot override a failed required check.

## Review

| Dimension | Risk-based questions | Required evidence | Rating | Reason |
| --- | --- | --- | --- | --- |
| Intent | Does the workflow solve bulk adjustment without adding excluded scheduling, conversion, or public API scope? | AC map, UI captures, route inventory | Pass | E-1 and E-4 show the accepted flow; the diff contains no excluded route or scheduler |
| Correctness | Does preview avoid writes, and do retry, restart, duplicate rows, and cancellation preserve exactly-once effects? | E-1, E-2, cancellation cases | Pass | Fixed fixtures and fault injection pass for the reviewed revision |
| Security | Are every read and state transition same-tenant and admin-only? Are audit events complete? | E-3 and Identity review | Pass | All negative matrix cases deny access and the four event contracts pass |
| Operability | Can operators observe, disable, resume, and recover the feature at the proposed cohort? | E-5, E-6, runbook | Revise for 100%; Pass for 25% | Cohort and kill-switch receipts pass. Database-failover proof is still missing |
| Maintainability | Are state ownership, contracts, tests, and decisions clear? | Schema, API contract, job-state tests, QB-ADR-31 | Pass | One state machine owns transitions; public and worker contracts are versioned |

## Hard gates

- [x] Required build, type, test, and contract checks pass.
- [x] No unresolved context blocker prevents implementation or 25% rollout.
- [x] Every acceptance criterion maps to evidence or an explicit unresolved
  result.
- [x] Required security and data-integrity checks pass.
- [ ] Database-failover recovery evidence meets the 100% release stage.

## Findings

| ID | Severity | Finding | Evidence | Owner | Resolution |
| --- | --- | --- | --- | --- | --- |
| F-1 | High for 100%; low for 25% | No environment receipt yet proves job recovery across database failover | E-6, C-3, R-6 | Priya Nair | Open; blocks 100% only |
| F-2 | Medium | The first mobile error list returned focus to the page heading instead of the first invalid-row summary | E-4 revision 1 | Admin Experience | Fixed and rechecked in E-4 revision 2 |
| F-3 | Low | Runbook did not name the owner allowed to re-enable the global flag | E-6 revision 1 | Reliability | Fixed; Priya Nair is named |

## Recommendation

Continue at 25%. Do not enable 100% until F-1 is closed by a passing database-failover
receipt and a new release-owner decision. This review supports the reviewed
revision and fictional staging environment only.
```

### Completed `05-evidence.md`

```md theme={null}
# Resumable bulk price-adjustment import: evidence

Status: Accepted for 25%; incomplete for 100%
Evidence owner: Aster, fictional coding agent, with named human reviewers
Revision proved: fictional commit `c6f42d9`; image digest
`sha256:9d7a...e031`
Environment: fictional `qb-staging-us-west`
Collected: 2026-07-22 through 2026-07-26

## Acceptance-criteria coverage

| Criterion | Evidence | Result | Remaining uncertainty |
| --- | --- | --- | --- |
| AC-1 | E-1, E-5 | Pass | Synthetic DS-100K, not production customer data |
| AC-2 | E-2 | Pass | The separate environment failover path remains under AC-6 |
| AC-3 | E-3 | Pass | None for the accepted route and event set |
| AC-4 | E-4 | Pass | VoiceOver and keyboard checks cover the defined flow, not every assistive technology |
| AC-5 | E-5 | Pass | Fictional staging numbers do not predict every production tenant |
| AC-6 | E-6 | Unresolved for 100% | 5% and 25% cohort plus kill switch pass; database failover not yet rehearsed |

## Receipts

### E-1: preview and no-write integration suite

- Supports: AC-1, P-1 through P-3, Intent and Correctness
- Revision: `c6f42d9`
- Environment and data: ephemeral test database plus synthetic DS-100K
- Command or procedure: `pnpm test:integration price-import-preview`
- Result: Pass
- Receipt: fictional artifact `receipts/E-1-preview-junit.xml` and database
  snapshots `E-1-before.sql.sha256` / `E-1-after.sql.sha256`
- Notes: 100,000 rows parsed; 84,913 valid; 14,870 unchanged; 217 rejected;
  zero billing-ledger rows changed. File size was 47.2 fictional MB.

### E-2: retry and worker-restart fault injection

- Supports: AC-2, P-1 and P-4, Correctness
- Revision: `c6f42d9`
- Environment and data: ephemeral job store and DS-100K valid-row result
- Command or procedure: `pnpm test:fault price-import-apply --retries=40`
- Result: Pass
- Receipt: fictional artifact `receipts/E-2-fault-injection.json`
- Notes: 40 seeded interruptions across claim, write, and acknowledge boundaries;
  84,913 valid adjustments produced 84,913 unique apply-ledger entries and
  84,913 billing effects. No duplicate effect was observed.

### E-3: tenant authorization and audit events

- Supports: AC-3, P-3 through P-5, Security
- Revision: `c6f42d9`
- Environment and data: route harness with two fictional tenants, four roles,
  and all import states
- Command or procedure: `pnpm test:security price-import-authz`
- Result: Pass
- Receipt: fictional artifact `receipts/E-3-authz-audit.xml`
- Notes: 96 negative cases denied. The start, confirm, cancel, and completion
  event shapes passed. Security reviewer Linh Tran recorded fictional review
  `QB-SEC-118`.

### E-4: interface, export, keyboard, and screen-reader review

- Supports: AC-4, P-3 and P-6, Intent, Correctness, Maintainability
- Revision: `c6f42d9`
- Environment and data: preview deployment with valid, rejected, running,
  canceled, failed, and completed fixtures
- Command or procedure: `pnpm test:e2e price-import-ui` followed by the packet's
  manual keyboard and VoiceOver script
- Result: Pass after one revision
- Receipt: fictional directory `receipts/E-4-ui/` containing 12 desktop/mobile
  captures, an accessibility report, keyboard transcript, VoiceOver notes, and
  rejected-row CSV assertion
- Notes: Revision 1 exposed F-2. Revision 2 restores focus to the invalid-row
  summary, announces progress without stealing focus, and passes the defined
  checks at 1440 by 900 and 390 by 844.

### E-5: fixed-dataset performance benchmark

- Supports: AC-1, AC-5, P-2 and P-7, Operability
- Revision: `c6f42d9`; DS-100K digest `sha256:2a31...0bc9`
- Environment and data: fictional `qb-staging-us-west`, isolated worker pool,
  20 preview and 20 apply runs
- Command or procedure: `pnpm bench price-import --dataset DS-100K --runs 20`
- Result: Pass
- Receipt: fictional report `receipts/E-5-benchmark.json`
- Notes: preview p95 71 seconds against a threshold below 90 seconds; apply p95
  4 minutes 12 seconds against a threshold below five minutes. These fictional
  staging results are not a universal performance claim.

### E-6: cohort, kill switch, and recovery

- Supports: AC-6, P-7 and P-8, Operability
- Revision: image digest `sha256:9d7a...e031`
- Environment and data: fictional `qb-staging-us-west` and eligible test tenants
- Procedure: follow `runbooks/price-import-rollout.md`
- Result: Partial
- Receipt:
  - fictional `receipts/E-6-5-percent.md`: Pass after 24 hours;
  - fictional `receipts/E-6-25-percent.md`: Pass after 48 hours;
  - fictional `receipts/E-6-kill-switch.md`: Pass, new work held in 23 seconds;
  - database-failover receipt: missing.
- Notes: No fictional guardrail crossed its runbook threshold. The missing
  failover rehearsal is U-1 and prevents 100% rollout.

## Visual and interaction evidence

| View or flow | Evidence | Result | Notes |
| --- | --- | --- | --- |
| Upload and oversize error, desktop/mobile | E-4 captures 01 through 04 | Pass | Limit and corrective action are visible |
| Preview with rejected rows | E-4 captures 05 and 06 | Pass | Export contains the same 217 rejected row IDs |
| Progress and cancel | E-4 captures 07 through 10 | Pass | Cancel disappears when commit begins |
| Keyboard-only flow | E-4 keyboard transcript | Pass | Focus issue fixed in revision 2 |
| VoiceOver flow | E-4 screen-reader notes | Pass | Status and row errors use names defined by the script |

## Performance and operational evidence

| Check | Dataset or load | Threshold | Result | Receipt |
| --- | --- | --- | --- | --- |
| Preview p95 | DS-100K, 20 runs | Below 90 seconds | Fictional 71 seconds, Pass | E-5 |
| Apply p95 | 84,913 valid rows, 20 runs | Below five minutes | Fictional 4 minutes 12 seconds, Pass | E-5 |
| 5% cohort | Eligible fictional tenants, 24 hours | No runbook guardrail breach | Pass | E-6 |
| 25% cohort | Eligible fictional tenants, 48 hours | No runbook guardrail breach | Pass | E-6 |
| Global kill switch | Queued and validating jobs | Hold new work within 60 seconds | Fictional 23 seconds, Pass | E-6 |
| Database failover | Applying job with seeded interruption | Resume with no duplicate effect | Not run, Unresolved | U-1 |

## Deploy or release proof

- Release stage: fictional 25% staging cohort
- Artifact: `sha256:9d7a...e031`
- Deployed by: fictional CI identity `qb-release`
- Started: 2026-07-22 16:00 UTC
- Observed through: 2026-07-26 16:00 UTC
- Health and guardrails: fictional error, queue-age, duplicate-key, audit-event,
  and billing-integrity dashboards remained within the runbook thresholds
- Rollback or kill switch: exercised successfully; F-3 corrected the named
  re-enable owner

## Unresolved failures

| ID | Related criteria | Failure or missing proof | Consequence | Owner | Next decision |
| --- | --- | --- | --- | --- | --- |
| U-1 | AC-6 | No environment receipt proves an applying job resumes safely after database failover | The packet cannot support 100% rollout | Priya Nair | Run the rehearsal on 2026-07-28, attach E-6 revision 2, and record a new release decision |
```

### Completed `06-decision-log.md`

```md theme={null}
# Resumable bulk price-adjustment import: decision log

Status: Active
Log owner: Rafael Ortiz
Last updated: 2026-07-26

## Decisions

### D-1: Use the existing durable job store

- Status: Accepted
- Date: 2026-07-15
- Author: Rafael Ortiz
- Decision: Use the existing fictional Postgres job store and lease model for
  validation and apply work.
- Rationale: It satisfies the accepted scope and QB-ADR-27. The idempotent apply
  ledger controls retry risk without adding a second queue or database.
- Evidence reviewed: accepted intent, C-2, QB-ADR-27, R-1, R-6
- Alternatives rejected:
  - Add a new managed queue: rejected because it expands architecture and
    operations before the existing lease model has failed the requirements.
  - Run the import in the browser request: rejected because request lifetime and
    interruption cannot satisfy resumability or the benchmark.
- Consequences:
  - The worker must tolerate an expired lease and replay.
  - Database failover must be rehearsed before 100% rollout.
- Supersedes: none
- Superseded by: none

### D-2: Make source-row identity the idempotency boundary

- Status: Accepted
- Date: 2026-07-16
- Author: Rafael Ortiz
- Decision: Require a stable `source_row_id` within each import and enforce a
  unique `(import_id, source_row_id)` apply-ledger key in the transaction that
  records the billing effect.
- Rationale: A job-level key cannot distinguish completed and pending rows after
  restart. The row boundary supports safe replay and a precise rejected-row
  result.
- Evidence reviewed: AC-2, QB-ADR-12, QB-ADR-27, R-1, E-2
- Alternatives rejected:
  - Hash the entire CSV as the only key: rejected because it cannot represent
    partial progress.
  - Treat retry as unlikely: rejected because QB-ADR-27 explicitly permits
    replay after lease expiry.
- Consequences:
  - Duplicate source row IDs are rejected during preview.
  - Accepted ledger entries remain immutable.
- Supersedes: none
- Superseded by: none

### D-3: Stage at 5%

- Status: Accepted
- Date: 2026-07-22
- Author: Priya Nair
- Decision: Enable the feature for the fictional 5% eligible-tenant cohort.
- Rationale: AC-1 through AC-5 pass. The rollout plan allows 5% before the
  failover rehearsal, and the global kill switch has a passing preflight.
- Evidence reviewed: E-1 through E-5, E-6 kill-switch preflight, rubric revision 1
- Alternatives rejected:
  - Enable 25% immediately: rejected because the plan requires 24 hours at 5%.
  - Hold all rollout for the failover rehearsal: rejected because that receipt
    is the accepted gate for 100%, not 5%.
- Consequences:
  - Reliability observes the cohort for 24 hours before another decision.
- Supersedes: none
- Superseded by: D-4

### D-4: Proceed to 25%

- Status: Accepted
- Date: 2026-07-23
- Author: Priya Nair
- Decision: Enable the fictional 25% cohort.
- Rationale: E-1 through E-5 pass. E-6 proves the 5% cohort and kill switch,
  satisfying the plan's gate for the next stage.
- Evidence reviewed: AC-1 through AC-5, E-1 through E-6, F-2, F-3
- Conditions:
  - Observe the 25% cohort for 48 hours.
  - Keep the kill switch armed.
- Alternatives rejected:
  - Enable 100%: rejected because the plan requires 25% observation and AC-6
    still lacks failover-recovery proof.
  - Stay at 5%: rejected because the accepted 5% gate passed.
- Consequences:
  - Reliability observes the 25% cohort before another release decision.
- Supersedes: D-3
- Superseded by: D-5

### D-5: Continue at 25% and hold 100%

- Status: Accepted
- Date: 2026-07-26
- Author: Priya Nair
- Decision: Keep the fictional 25% cohort enabled. Hold 100% rollout.
- Rationale: E-6 proves 48 hours at 25% and the kill switch. U-1 leaves AC-6
  unresolved for 100%, so the evidence does not support full rollout.
- Evidence reviewed: AC-1 through AC-6, E-1 through E-6, F-1 through F-3, U-1
- Conditions:
  - Run the database-failover rehearsal.
  - Attach E-6 revision 2 to the same artifact digest or rerun affected evidence
    for a changed revision.
  - Record a new release-owner decision before 100%.
- Alternatives rejected:
  - Enable 100%: rejected because AC-6 lacks recovery proof.
  - Roll back 25%: rejected because no current integrity, security, performance,
    or cohort gate failed.
- Consequences:
  - The feature remains available to 25% with the kill switch armed.
  - No document may describe the rollout as complete.
- Supersedes: D-4
- Superseded by: none
```

## Adapt the packet without weakening it

You can merge files for a small change if the jobs remain distinct. For example, put a short rubric and decision at the end of the plan, but do not turn missing evidence into a prose claim.

You can also link to existing documents instead of copying them:

* link a maintained [PRD](/templates/product-requirements-document) from `01-intent.md`;
* link a durable [technical specification](/templates/technical-specification) from `02-context.md`;
* link one accepted [ADR](/templates/architecture-decision-record) or a discussion-stage [RFC](/templates/software-rfc);
* link the immediate [AI coding plan](/templates/ai-coding-plan) from `03-plan.md`;
* link exact test reports and review artifacts from `05-evidence.md`.

The packet should stay an index to current authority and inspectable proof. It should not become a second copy of the whole project.
