Factory docs, home
Page navigation

Reference document, shown as written except that local paths appear as placeholders. Where it describes the Factory as intended, read it as design, not current state: only local infrastructure is accepted, no release, customer value or scheduled automation is established, and all 27 customer-value epics remain open. Current state: Factory model.

Each registered Product can hold core values: 0–6 ordered values, each a short statement and an application, the concrete rule for choosing between development options. Source: src/project-guidance.ts. Edited in the dashboard at /projects/:id/values.

What guidance is. Values are the owner's stated intent for a Product. They are locally saved guidance, not calibrated doctrine. They grant no delivery Authority, and they never override acceptance, budget or safety constraints. They are never copied between Products, and they write nothing into a Product's files. An empty or cleared list is not a gate, and removes no existing constraint.

What guidance is not yet. Nothing in the factory reads values automatically. No planner, brief builder or provider consumes them. The contract below is ready for a future brief to pin; this increment demonstrates only that pins stay stable and reviewable.

Storage

  • Aggregate. guidance:product:<productId> in the Portfolio journal, written only through CommandJournal.execute. The aggregate version is the revision.
  • Revisions. Revision 0 means unset. Every accepted command records exactly one new revision, including one that clears the list. Each revision is one guidance.values-set event, and history is never rewritten.
  • Bounds. At most 500 revisions per Product (LIMIT beyond that). Each text field is 1–280 printable single-line characters. The canonical payload is at most 16 KiB.
  • Value IDs. [a-z0-9][a-z0-9-]{0,39}, unique within a revision. An ID stays the same when the value is reworded or reordered.
  • Registration. The Product must be registered. Guidance never reads the checkout, so a missing or unreadable repository does not block editing.

Provenance

Each revision records where its values came from, and the digest includes it:

originMeaningnote
direct-entryTyped by a person. Every dashboard edit is recorded this way; the HTTP API refuses any other value.Optional
document-summarySummarised from a document, not entered directlyRequired: names the document

Provenance records the origin of the input. It says nothing about identity or authority. A summary does not become calibrated doctrine by being saved.

API

const guidance = new ProductGuidance(journal, { now? });

guidance.setValues({ commandId, productId, expectedRevision, values, provenance? }): SetValuesResult
guidance.current(productId): GuidanceSnapshot
guidance.revision(productId, revision): GuidanceSnapshot
guidance.history(productId, { before?, limit? }): GuidanceHistory       // newest first, 1-20 per page
guidance.resolvePin({ productId, revision, digest }): GuidanceSnapshot
guidanceDigest(productId, values, provenance): string

A GuidanceSnapshot is { protocol: "product-guidance/1", productId, revision, digest, recordedAt, provenance, values }, deeply frozen. digest is SHA-256 over canonical { protocol, productId, values, provenance }. It excludes the revision number, so a pin carries both.

Commands

SituationResult
New command ID at the current revisionA new revision
Same ID, same Product, expected revision, values and provenanceThe recorded result with replayed: true, even after later revisions. Nothing is written.
Same ID with anything differentCONFLICT
expectedRevision is not currentSTALE, with currentRevision. Nothing is merged, rebased or retried.
Invalid input or an unregistered ProductINVALID or NOT_FOUND, and nothing is written

Identical content under a new command ID is still a new revision; no content shortcut bypasses command receipts.

Integrity

Every read re-validates each event's digest and checks that the aggregate's state is exactly its last recorded revision. Every result is checked against its request, and a replayed result against the revision it recorded. A mismatch is CORRUPT for that Product only: nothing is returned as a valid snapshot or pin, and no edit writes over it.

For future briefs

A brief that uses guidance should:

  1. pin { productId, revision, digest } from current();
  2. present the applicable values' application rules;
  3. explain any material trade-off made against them.

Resolve the pin with resolvePin. A later edit never changes what an existing pin resolves to; new planning uses the new revision. A pin whose digest does not match is refused (CONFLICT), never upgraded. Values cannot widen authority; dispatch eligibility belongs to the later Product gate.

Tests

FileCovers
test/project-guidance.test.tsRestart and history; rewording and reordering keep IDs; clearing is a revision; replay after later edits; changed-command conflict; stale writes nothing; two real processes at one revision; invalid, oversized, unregistered and cross-Product input writes nothing; unavailable checkout; pin stability; provenance; state, history and receipt disagreement is CORRUPT and never overwritten
test/dashboard-guidance-attention.test.tsThe HTTP command: guards, bounds, restart and replay, STALE and CONFLICT, direct-entry provenance
test/dashboard-editor.test.tsThe editor keeps one operation ID for a retry, mints a new one for any change, classifies failures and describes conflicts

Source: docs/project-guidance.md