Skip to content

Product-law layer: domain invariants + product model (Domain & Product agents)#97

Merged
gbrbks merged 17 commits into
mainfrom
feature/domain-invariants
Jun 11, 2026
Merged

Product-law layer: domain invariants + product model (Domain & Product agents)#97
gbrbks merged 17 commits into
mainfrom
feature/domain-invariants

Conversation

@gbrbks

@gbrbks gbrbks commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

What

Adds a product-law layer to /archie-deep-scan so the generated rules capture what the product must do, not just how the code is shaped. Two new agents, a new rule kind, three new blueprint sections, and a Product section in the viewer.

  • Wave 1 — Domain agent (always runs): extracts observed product laws (domain_invariants), cite-or-omit. States each law as a product rule (what the product guarantees) with the code-level how in a separate mechanism field. Tags each law domain_role (core / supporting / platform) and rations supporting subsystems so monetization/auth code can't crowd out the core.
  • Wave 2 — Product agent (full scan, when laws exist): reasons over the observed laws to produce product_model (a product overview + value workflow), derived_invariants (reasoned laws, ≥2-anchor derivation), and unenforced_invariants (an advisory, clearly-labeled gap list — never enforced).
  • domain_invariant rule kind (Step 6): observed laws → decision_violation (block), derived → tradeoff_undermined (warn). Enforced by the existing severity-gated hook, no hook change.
  • Render + viewer: product-laws.md (two tiers: grounded vs ⚠️ unverified, grouped core-first) + product-model.md; a new PRODUCT menu group in the viewer (Product Overview, Product Laws, Unverified Gaps) with the grounded/ungrounded distinction drawn identically across markdown and UI.

Works on apps, libraries/SDKs, services, and CLIs (the agents classify the repo type and frame the core workflow accordingly). Data agent is now always-on alongside Domain (only the UI Layer agent is optional).

Why

Prior rules were deep but structural ("wrap an adapter in a transaction", "where files live") — none captured product correctness. This layer adds the missing tier: grounded, accurately-cited product laws (balance never negative, idempotent ingest, immutable issued records, tenant scoping, etc.).

Validation

Iteratively validated against a real codebase: laws verified accurate against source, distribution flipped core-first (subscription rationed), workflow renders as titled steps, entities deduplicated against Data Models, summary readable. 896 tests pass; verify_sync clean; CC + Codex parity preserved (single-model-per-wave); comprehensive mode lifts all caps.

Notes

  • Pre-existing test-bed references elsewhere in the repo were intentionally left untouched; all new content is test-bed-free.
  • mechanism field + behavioral-altitude framing land on the next scan (prompt-driven); structure and rendering are in place.

🤖 Generated with Claude Code

gbrbks and others added 17 commits June 10, 2026 11:41
…ugh the pipeline

Phase 1 foundations for product-level rule synthesis:
- rule_kinds.py: register domain_invariant kind + inv-/der- id-prefix map
- _common.py normalize: coerce product_model (dict) + domain_invariants/
  derived_invariants/unenforced_invariants (lists), preserving content
- finalize.py: reset the Wave-2 product sections on full re-run (--from 5
  redo-safety); domain_invariants (Wave 1) intentionally preserved
- merge.py is section-agnostic (generic deep_merge) — no change needed
- golden fixture + pipeline tests (generic invented domain, no test-bed data)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t-laws markdown

Phase 2 (consumers, Python side):
- step-6-rule-synthesis.md: domain_invariant kind, 2 coverage rows
  (domain_invariants/derived_invariants), severity policy (stated->block,
  derived->warn, promotion gate), entity+category dedup with domain_invariant
  as canonical carrier, and explicit exclusion of product_model +
  unenforced_invariants from rule sources. Quality-over-quantity quota reframe.
- renderer.py: product-model.md (domain map) + product-laws.md (two tiers:
  enforced/grounded vs unverified/ungrounded with searched proof-of-work);
  Product Laws summary + links in AGENTS.md. domain_invariant enforcement
  rules group into by-topic/ for free via rule_kinds.
- CLI viewer.py needs no change — serves the whole blueprint to the React app.
- Tests: renderer two-tier output, gap-never-in-grounded, step-6 contract,
  domain_invariant round-trip (extract_output -> classify -> index).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eport

Phase 2 (consumers, React side — shared by the local viewer and the share report):
- ReportSections.tsx: ProductModelSection (domain map), ProductLawsSection
  (grounded tier: domain_invariants + derived_invariants with resolved
  premise links + enforced-at citations), UnverifiedInvariantsSection
  (distinct amber 'unverified' surface, per-card warning badge, searched[]
  list for falsifiability). Grounded vs ungrounded drawn unmistakably.
- ReportPage.tsx: pull the four bp sections (guarded), render between
  trade-offs and guidelines, register nav + scroll-spy ids.
- fixPrompt.ts: resolve a derived law's derived_from back to its premises.
- Mirrored to archie/assets/viewer + npm-package/assets/viewer (verify_sync).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…product laws

Phase 3 (producers + dispatch wiring):
- step-3-wave1/domain-agent.md: observes product correctness laws (cite-or-omit,
  7-category taxonomy, self-discovered entities, test-read exception); emits
  domain_invariants. step-5d-product.md: reasons over them to emit product_model
  + derived_invariants (>=2-anchor derivation guardrail) + unenforced_invariants
  (the gap list, required searched proof-of-work, never a rule).
- Wave 1: Data and Domain now ALWAYS spawn (only UI Layer is optional) — per
  policy that the fact-gathering agents must not be gated on a heuristic; a
  no-data repo just yields empty arrays. Updates orchestration, dispatch table,
  timing keys, comprehensive line, incremental emit list, step-4 merge.
- Wave 2: Product is the 4th reasoning agent, gated on domain_invariants being
  non-empty (driven by Domain's actual output, not a heuristic). finalize lists
  the product file unconditionally (warns+skips when absent). Design now links
  decisions to the laws they preserve (forced_by/enables); Risk turns laws into
  pitfalls. Single-model-per-wave preserved (Codex-safe).
- Mirrored to npm-package; verify_sync + full suite (800) green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…trip test

Phase 5 hardening:
- CLAUDE.md: Wave 1 (Data+Domain always, UI optional), Wave 2 (4 agents incl
  Product), blueprint data model lists the product-law sections + which are
  enforced vs informational.
- integration test: Wave-1 domain_invariants + Wave-2 product sub-file flow
  through finalize() into blueprint.json + rendered product-laws.md (both tiers).
- Full suite 801 green; verify_sync green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adversarial validation of the feature surfaced three real gaps (now fixed +
guarded by tests):
- step-6: enforced_at entries are file:line citations, not globs — the prompt
  now tells the agent to strip :line and broaden to a dir glob when deriving
  triggers.path_glob, else the hook trigger silently never matches.
- step-5: the Product spawn gate ('domain_invariants non-empty') had no concrete
  evaluation mechanism for the orchestrator — added an explicit DOMAIN_LAW_COUNT
  python -c check (auto-approved form), mirroring the telemetry count pattern.
- step-5: Product now runs in FULL mode only. derived_invariants/unenforced are
  global reasoning, not per-change deltas; a patch merge would append duplicate
  ids on a changed law. Incremental keeps observed domain_invariants fresh
  (Wave 1); the reasoned layer refreshes on the next full scan.

Verified clean: hook enforces domain_invariant rules via severity_class
(kind-agnostic, blocks/warns + surfaces forced_by/enables/alternative); viewer
bundle passes the whole blueprint; viewer tsc --noEmit exit 0. Suite 803 green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Three independent reviewers (wiring, python-correctness, intent/parity) audited
the branch. Fixes for what they found:

- BLOCKER (incremental): merge.py --patch now upserts domain_invariants/
  derived_invariants/unenforced_invariants by `id` (keep patch version). Without
  this, an incremental scan re-emitting a changed law APPENDED a duplicate id
  (deep_merge dedups by `name`; these are id-keyed). Regression test added.
- MAJOR (docs): orchestration.md had stale 'as applicable' + 'sub5 absent when
  has_persistence_signal == false' wording that contradicted the always-run
  change. Fixed the dispatch-model line, the timing-fold enumeration (was missing
  Domain), and the no-op example.
- MINOR (renderer): AGENTS.md product-laws summary no longer emits a dangling
  header on a derived-only blueprint (lists derived laws too); 'N more' count is
  computed from what was shown (correct under --comprehensive); empty-invariant
  entries are skipped instead of rendering '- ****'. Regression tests added.

Verified non-issues by the reviewers: field-name consistency across agents/
renderer/viewer, gap-list never a rule, parity (single-model-per-wave), depth
caps reach both agents, zero test-bed leakage in new lines, viewer tsc exit 0.
Suite 806 green; verify_sync green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…in_role

The Domain agent over-indexed on densely-guarded subsystems (monetization/auth):
laws cluster where guard code is dense, not where product value lives. Fix:

- Domain agent: anchor to the product's PRIMARY VALUE WORKFLOW first; tag every
  law with domain_role (core | supporting | platform); mine the core's data-flow
  / computation invariants (not just guards) so the core isn't starved; in
  default depth, core has NO cap while supporting subsystems are rationed to
  ~2-3 each and platform to ~1-2. COMPREHENSIVE depth lifts ALL caps (no
  suppression) per user directive.
- Product agent: derived_invariants inherit domain_role from their anchors.
- renderer: product-laws.md groups the grounded tier by role (Core first, then
  Supporting, then Platform), with a flat fallback for blueprints predating the
  field; AGENTS.md summary sorts core-first so the capped list leads with core.
- web viewer (ProductLawsSection): same role grouping + flat fallback.
- Tests: role-grouping order, flat fallback, domain-agent distribution prompt.

Suite 809 green; verify_sync green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s, new Product menu

Per user feedback on the Product Model screen:
- Drop product_model.entities everywhere (prompt + renderer + viewer) — the Data
  Models section already inventories models in detail; entities here were noise.
- product_model.summary is now a detailed 3-6 sentence product description
  (prompt change), rendered as prose, not a cramped pill.
- core_workflow is now [{title, description}] (was bare strings) — rendered as
  numbered titled cards in the viewer and numbered titled steps in product-model.md;
  both renderer and viewer accept the legacy string shape for backward compat.
- Viewer: new sidebar group 'PRODUCT' (Product Overview, Product Laws, Unverified
  Gaps) moved out of DESIGN; 'Product Model' renamed 'Product Overview'.
- Tests updated for the new shape + a legacy-string compat test. 889 green; sync clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ty removal

The Product agent under-complied last run: it emitted core_workflow as plain
strings (rendered as fake 'Step N') and still emitted entities, despite the
prompt. Confirmed via timing the new prompt WAS used — so this is agent
under-compliance, not a stale prompt.

- normalize: deterministically strip product_model.entities — guarantees entities
  never render regardless of agent compliance (Data Models is the canonical
  inventory).
- step-5d prompt: hard, contrastive STRICT block — core_workflow items are
  OBJECTS {title,description}, NEVER bare strings (with wrong/right example).
- viewer: legacy string steps render description-only (no fabricated 'Step N').
- tests updated; 894 green; sync clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…iour, not code

Two conceptual corrections from user feedback:
- Archie runs on libraries/SDKs/services/CLIs too, not just end-user apps. The
  Domain + Product agents now first classify what the repo IS and frame the
  core + workflow accordingly: app=user journey, library=consumer call path,
  service=request lifecycle, CLI=invocation->effect. summary + core_workflow
  generalized to capability/consumer language.
- Product Laws were reading as engineering notes (e.g. 'getLocationType() maps
  CURRENT_POSITION_HOME_ID -> POSITION'). New behavioural-altitude rule: the
  invariant SENTENCE must state product behaviour a user/consumer relies on,
  understandable without the source; function/enum/class internals move to
  enforced_at/evidence. Wrong/right contrast uses the exact reported example.
  Applied to both observed (Domain) and derived (Product) laws.

Pure prompt/altitude change; effect materializes on next re-scan. 896 green; sync clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ule'

Per user feedback: don't define the law-altitude rule by negation against
'engineering' — frame it positively about the product. Reworded the Domain +
Product agent guidance to lead with what a law SHOULD be (a product rule: what
the product guarantees for its user/consumer, in the domain's own words, that a
product owner would recognise) and let the enforcing code live in
enforced_at/evidence. Dropped all 'not engineering' / 'not code mechanics'
phrasing. Step-lint now asserts the prompt contains no 'engineering' wording.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… in summary

Prose alone failed to keep code out of the law sentence (3rd try) — so apply the
structural fix that worked for the workflow shape: give the code its own field.
- Domain + Product law schema: new 'mechanism' field. invariant = the product
  rule (product concepts only, no function/constant names); mechanism = how the
  code enforces it. The product-rule guidance now points all code detail there.
- renderer: mechanism renders as a secondary 'How it's enforced:' line under each
  law (observed + derived).
- viewer: mechanism shown de-emphasized under each law card; AND the Product
  Overview summary + workflow descriptions now render inline markdown via a local
  renderInlineMd helper (fixes literal '**BabyWeather**' asterisks).
- fixture + tests cover mechanism render + the schema field. 896 green; sync clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…width, lead)

The summary rendered as one dense full-width block. Now: split on blank lines
into paragraphs (max-w-2xl reading column, ~65ch), first paragraph emphasized as
a lead, the rest muted body — each still through renderInlineMd for bold/code.
Prompt nudged to write the summary as 2-4 short blank-line-separated paragraphs
so future scans are naturally scannable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…de leak)

Replace 'weatherHourly[selectedHourIdx]' (a real identifier from the test repo)
with a generic 'items[selectedIndex]' placeholder in the Domain agent prompt.
No test-bed specifics in committed Archie artifacts.
@vercel

vercel Bot commented Jun 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
archie Ready Ready Preview, Comment Jun 11, 2026 10:37am
archie-viewer Ready Ready Preview, Comment Jun 11, 2026 10:37am

@gbrbks gbrbks merged commit 923cb7e into main Jun 11, 2026
4 checks passed
@gbrbks gbrbks deleted the feature/domain-invariants branch June 11, 2026 10:38
gbrbks added a commit that referenced this pull request Jun 11, 2026
Product-law layer (PR #97): domain invariants + product model — Domain (Wave 1)
and Product (Wave 2) agents, domain_invariant rules, two-tier product-laws +
Product viewer section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant