State Model - AFPS Tracker

Review page for the proposed logical domain/state/contract model for AFPS Tracker's first repo read-through. This page proposes canonical writes to design/afps-tracker/domain-model-afps-tracker.md, design/afps-tracker/model-tree-afps-tracker.yaml, and branch model_ref attachments in design/afps-tracker/flow-tree-afps-tracker.yaml, but no canonical state-model artifacts have been written yet.

status: review date: 2026-07-02 product path: research/afps-tracker visual tier: visual

Table Of Contents

Decision Summary

5framework intermediates synthesized
6approved flow nodes covered
2aggregate roots: Portfolio and ProductPath
7stateful subjects modeled

The proposed model keeps AFPS Tracker passive and read-first. Canonical truth remains in AFPS artifacts; the tracker models source-derived workflow state, claim support, diagnostics, and handoff readiness without owning storage, endpoints, auth, migrations, or deployment decisions.

Recommended approval: approve the model as the logical substrate for all six approved first-read-through branches. The riskiest model choice, making ProductPath the primary aggregate root, is consistent across all five frameworks and keeps source artifacts, claims, diagnostics, and handoffs interpreted through the selected path.

Framework Inputs

OrderFrameworkCanonical contributionIntermediate
1event-modelingTimeline of scan, source resolution, diagnostic evaluation, trust degradation, boundary explanation, and handoff generation.design/afps-tracker/state-model-afps-tracker/event-modeling.md
2domain-modelDDD spine: ProductPath primary aggregate, Portfolio thin orientation aggregate, first-class claim/evidence/provenance/diagnostic/handoff elements.design/afps-tracker/state-model-afps-tracker/domain-model.md
3state-machineLifecycle states, transitions, guards, UI-state mappings, warning preservation, blocking diagnostics, and boundary suppression.design/afps-tracker/state-model-afps-tracker/state-machine.md
4data-modelLogical ERD with repository context, portfolio snapshot, path refs, product paths, artifacts, claims, evidence, provenance, diagnostics, and handoffs.design/afps-tracker/state-model-afps-tracker/data-model.md
5contract-mapLogical command/query contracts and shared response types, especially TrustEnvelope, DiagnosticRef, and HandoffBoundary.design/afps-tracker/state-model-afps-tracker/contract-map.md

Proposed Domain Model

This is the proposed full content for design/afps-tracker/domain-model-afps-tracker.md.

---
skill: state-model
status: proposed
topic: afps-tracker
product_path: research/afps-tracker
flow_tree: design/afps-tracker/flow-tree-afps-tracker.yaml
model_tree: design/afps-tracker/model-tree-afps-tracker.yaml
alignment_page: alignment/state-model-afps-tracker.html
---

# AFPS Tracker Domain Model

## Scope

AFPS Tracker models the first repo read-through for an AFPS-style repository. The operator opens a repository, orients across active and parallel product paths, verifies selected-path stage/status/reason/evidence/provenance, recovers from diagnostics, and leaves with a source-backed handoff or boundary explanation.

The model is logical only. It describes entities, states, events, commands, queries, read models, policies, and logical request/response/error shapes. It does not define storage engines, real endpoints, URLs, authentication, authorization, migrations, indexes, file watchers, deployment, or high-fidelity UI.

## Ubiquitous Language

- Product path: source-derived AFPS product/research path, usually scoped under `research/{slug}`.
- Portfolio: repo-local collection of active, parallel, inactive, excluded, and unresolved product path references.
- Source artifact: canonical AFPS file or generated artifact used as evidence or provenance.
- Source-backed claim: displayed or handoffable assertion with traceable source support or an explicit caveat.
- Evidence link: claim-to-source reference, including unresolved or contradictory support.
- Provenance record: approval, canonicalization, amendment, archive, review, or working-packet lineage.
- Diagnostic issue: trust degradation item scoped to source, claim, path, portfolio, or handoff level.
- Trust level: clean, warning, blocked, partial, inferred, unsupported, contradicted, source-backed, explanatory, or out-of-scope.
- Parser confidence: certainty of extraction or mapping from source artifacts.
- Source confidence: confidence that source/provenance supports a claim.
- Handoff eligibility: clean-copy, warning-copy, blocked, explanatory, promoted-boundary, out-of-scope, or unavailable.
- Boundary kind: inactive, archived, deferred, revisit-candidate, promoted, out-of-scope, unsupported, or unresolved.

## Aggregate Roots

### Portfolio

Thin orientation aggregate for a repo-local read-through. It groups source path references, active path refs, inactive/boundary refs, and unresolved refs.

Invariants:

- Active path refs must resolve to product path records or explicit unresolved diagnostics.
- Archived, deferred, revisit-candidate, promoted, `_archive`, and out-of-scope refs remain visible but cannot silently become active route targets.
- Portfolio-level source health is displayed separately from selected-path trust.

Flow bindings: `uf-orient-portfolio` reads/displays; `uf-recover-diagnostics` transitions; `uf-explain-boundaries` reads excluded refs.

### ProductPath

Primary aggregate root for selected-path interpretation. It owns path identity, source state, stage, reason, next skill, evidence/provenance refs, derived trust, diagnostics, handoff eligibility, and boundary explanation.

Invariants:

- A path fact is clean only when source artifacts, evidence links, or provenance support it.
- Missing, contradictory, stale, inaccessible, or low-confidence source facts degrade trust instead of being hidden.
- Inactive, promoted, unresolved, blocked, out-of-scope, unsupported, or contradicted paths cannot emit a normal clean next-skill handoff.
- Warning or partial handoffs must preserve warnings and diagnostic refs.

Flow bindings: all six user-flow nodes read, display, write, or transition through this aggregate.

## Entities And Value Objects

| Element | Kind | Key attributes | Relationships | Lifecycle |
| --- | --- | --- | --- | --- |
| RepositoryContext | entity | repository_ref, scan_started_at, scan_completed_at, scan_state, source_health, warnings | one optional PortfolioSnapshot; many SourceArtifacts and DiagnosticIssues | Portfolio scan state |
| PortfolioSnapshot | entity/read model | snapshot_id, progress_manifest_ref, snapshot_state, active_path_refs, excluded_path_refs, parser_confidence, source_confidence | many PortfolioPathRefs and ProductPaths | Portfolio state |
| PortfolioPathRef | entity | path_ref_id, path_id, scope_path, source_status, resolution_state, boundary_kind, diagnostic_refs | resolves to zero or one ProductPath | Ref resolution state |
| ProductPath | aggregate-root | path_id, label, scope_path, source_status, pipeline_stage, reason, next_skill, revisit_trigger, last_touched, path_state, trust_level, handoff_eligibility, boundary_kind | many SourceArtifacts, SourceBackedClaims, EvidenceLinks, ProvenanceRecords, DiagnosticIssues, HandoffSummaries | Product path state |
| SourceArtifact | entity | artifact_id, artifact_ref, artifact_kind, source_role, read_status, approval_status, freshness_state, parser_confidence, source_confidence, warnings | supports claims, evidence, provenance, diagnostics | Source artifact state |
| SourceBackedClaim | entity | claim_id, claim_kind, claim_text, support_status, parser_confidence, source_confidence, trust_level, derived_from, warnings | has zero or many EvidenceLinks and DiagnosticIssues | Claim support state |
| EvidenceLink | entity/value slice | evidence_link_id, claim_id, evidence_ref, resolved_ref, resolution_state, support_status, read_status, source_hint, warnings | links claim to zero or one SourceArtifact | Evidence link state |
| ProvenanceRecord | entity/value slice | provenance_id, provenance_ref, provenance_kind, approval_state, decision_summary, canonical_target, archive_refs, confidence, warnings | supports claims and handoffs | Provenance state |
| DiagnosticIssue | entity | issue_id, issue_kind, severity, level, state, affected_refs, affected_claims, affected_paths, handoff_impact, recommended_manual_check | affects source, claim, path, portfolio, or handoff | Diagnostic issue state |
| HandoffSummary | entity/read model output | summary_id, handoff_type, copy_state, confidence, next_skill, branch_state_explanation, handoff_boundary, included refs, blocked_reasons | reads ProductPath, claims, evidence, provenance, diagnostics | Handoff summary state |

## State Machines

### Portfolio

States: `unscanned`, `scanning`, `no-afps-state`, `manifest-malformed`, `paths-discovered`, `partial`, `source-backed`, `blocked`.

Key transitions:

- `unscanned -> scanning` on `ScanPortfolio`.
- `scanning -> no-afps-state` on missing progress/product-path state.
- `scanning -> manifest-malformed` on malformed source.
- `scanning -> paths-discovered` when product path records or refs are interpretable.
- `paths-discovered -> partial|source-backed|blocked` after diagnostic classification.

UI state mappings: empty initial frame, loading portfolio overview, empty/no-manifest state, grouped path rows, partial/warning badges, clean portfolio overview, blocking portfolio diagnostic.

### ProductPath

States: `undiscovered`, `discovered`, `selected`, `source-inventorying`, `source-backed`, `partial`, `warning`, `blocked`, `inactive`, `promoted-boundary`, `out-of-scope`.

Key transitions:

- `undiscovered -> discovered` when a source record exists.
- `discovered -> selected` on `ProductPathSelected`.
- `selected -> source-inventorying` when scoped artifacts, evidence, provenance, diagnostics, and next skill are resolved.
- `source-inventorying -> source-backed|partial|blocked` from source and claim support.
- `source-backed -> warning|blocked` when diagnostics appear.
- `discovered|selected -> inactive|promoted-boundary|out-of-scope` when boundary policy suppresses normal routing.

UI state mappings: portfolio row, detail loading, clean selected-path detail, partial badges, warning detail, blocked diagnostics, inactive/promoted/out-of-scope explanation.

### SourceArtifact

States: `referenced`, `resolving`, `found`, `parsed`, `confirmed`, `review-only`, `amended`, `archived`, `missing`, `unreadable`, `malformed`, `stale`, `unsupported`.

UI state mappings: source ref row, source loading row, resolved source path, parsed facts, confirmed/review/amended/archive badges, missing/unreadable/malformed/stale/unsupported diagnostics.

### EvidenceLink

States: `unresolved`, `resolving`, `resolved`, `supports-claim`, `partially-supports-claim`, `contradicts-claim`, `inaccessible`.

UI state mappings: unresolved evidence marker, evidence loading marker, resolved evidence path/section, source-backed claim badge, partial support badge, contradiction warning/blocker, inaccessible warning.

### ProvenanceRecord

States: `missing`, `discovered`, `review`, `confirmed`, `amended`, `archived`, `partial`, `contradicted`.

UI state mappings: missing provenance warning, pending provenance row, review caveat, confirmed approval badge, amended badge, archive marker, partial provenance badge, contradiction blocker.

### DiagnosticIssue

Severity states: `none`, `raised`, `classified`, `warning`, `blocked`, `partial`, `resolved-by-source-review`.

Affected-level states: `source-level`, `claim-level`, `path-level`, `portfolio-level`, `handoff-level`.

Synthesis rule: severity and affected level are orthogonal fields and must not be flattened into one ambiguous status.

### HandoffSummary

States: `unavailable`, `requested`, `clean-copy`, `warning-copy`, `blocked`, `explanatory`, `promoted-boundary`, `out-of-scope`, `copied`, `suppressed`.

UI state mappings: disabled/absent handoff area, preparation state, clean copy-ready summary, warning copy-ready summary, blocked summary with reasons, boundary explanation, copy success, suppressed copy state.

## Events

Repository and portfolio events: `RepositoryScanStarted`, `ProgressManifestLocated`, `ProgressManifestMissing`, `ProgressManifestParsed`, `ProgressManifestMalformed`, `ActivePathsNormalized`, `ProductPathRecordDiscovered`, `ProductPathRecordExcluded`, `ActivePathReferenceUnresolved`.

Selection and source events: `ProductPathSelected`, `ScopedSourceInventoryStarted`, `ScopedResearchArtifactResolved`, `ScopedResearchArtifactMissing`, `EvidenceRefResolutionStarted`, `EvidenceRefResolved`, `EvidenceRefUnresolved`, `ClaimInspectionRequested`, `ClaimSupportEvaluated`, `SourcePreviewPrepared`, `SourcePreviewUnavailable`.

Provenance events: `ProvenanceRecordDiscovered`, `ProvenanceRecordConfirmed`, `ProvenanceRecordReviewOnly`, `ProvenanceRecordArchived`, `ProvenanceRecordMissing`.

Diagnostic and trust events: `DiagnosticIssueRaised`, `DiagnosticIssueClassified`, `TrustLevelChanged`, `HandoffEligibilityChanged`, `NextSkillCandidateDetected`, `NextSkillCandidateSuppressed`.

Handoff and boundary events: `HandoffGenerationRequested`, `HandoffSummaryPrepared`, `CleanCopyPrepared`, `WarningCopyPrepared`, `HandoffBlocked`, `HandoffCopyRequested`, `HandoffCopied`, `HandoffCopySuppressed`, `BoundaryExplanationRequested`, `PromotedBoundaryDetected`, `InactivePathExplained`, `OutOfScopeRequestExplained`.

## Commands And Queries

Commands:

- `ScanPortfolio`: starts repo-local source read-through and derives portfolio orientation.
- `SelectProductPath`: establishes selected-path context.
- `EvaluateDiagnostics`: classifies source, claim, path, portfolio, and handoff issues.
- `GenerateHandoff`: prepares clean, warning, blocked, explanatory, promoted-boundary, or out-of-scope handoff output.
- `CopyHandoff`: records logical copy/export attempt and suppression reasons when copying is not allowed.

Queries:

- `ListPortfolioPaths`: returns grouped portfolio state.
- `GetSelectedPathDetail`: returns source-backed detail for one selected path.
- `InspectEvidenceRef`: resolves and classifies claim-to-source evidence.
- `InspectProvenance`: returns approval, canonicalization, amendment, archive, and review lineage.
- `GetDiagnostics`: returns current diagnostic state scoped to portfolio, path, claim, source, or handoff.
- `ExplainBoundary`: explains inactive, promoted, out-of-scope, unresolved, unsupported, or contradicted path state without normal active routing.

Shared logical response types: `RepositoryContextInput`, `ProductPathSelector`, `ArtifactRef`, `ClaimRef`, `TrustEnvelope`, `DiagnosticRef`, and `HandoffBoundary`.

## Read Models

- Portfolio Overview: scan status, active paths, grouped path refs, source health, warnings, parser confidence.
- Selected Path Detail: selected path facts, refs, confidence, claims, diagnostics, handoff eligibility, available and blocked actions.
- Evidence Inspector: claim ID/text, evidence link, resolved ref, support status, source hint, trust, diagnostics, preview availability.
- Provenance Timeline: approval/canonical/amend/archive/review records, confidence, warnings, diagnostics, handoff relevance.
- Diagnostics Panel: issues by severity and level, affected sources/claims/paths, handoff impacts, manual checks, trust changes.
- Handoff Summary: handoff type, copy state, next skill when permitted, explanation, refs, warnings, blockers, boundary.

## Policies

- Source Truth Policy: displayed facts and handoff claims must be source-backed or explicitly labeled derived, inferred, unsupported, partial, or contradicted.
- Active Path Resolution Policy: active refs must resolve to non-excluded product path records or visible unresolved diagnostics.
- Evidence Support Policy: source-backed labels require readable artifacts, mapped fields/sections, approval records, or source hints.
- Provenance Confidence Policy: confirmed provenance requires confirmed alignment or canonical artifact evidence; review-only remains partial.
- Diagnostic Severity Policy: degrade trust at the narrowest affected level before escalating to path or handoff.
- Handoff Eligibility Policy: clean copy requires source-backed next work and no blocking diagnostics; warning copy preserves caveats; inactive/promoted/out-of-scope/unresolved/contradicted paths produce explanatory or blocked handoffs.
- Boundary Preservation Policy: promoted development/execution work remains outside AFPS Tracker unless a separate flow owns it.
- Confidence Separation Policy: parser confidence and source confidence remain separate fields.
- Next Command Suppression Policy: promoted, inactive, out-of-scope, unsupported, contradicted, blocked, or source-insufficient states suppress normal next-command output.

## Flow Binding Matrix

| Flow node | Reads | Writes/triggers | Displays | Transitions |
| --- | --- | --- | --- | --- |
| `uf-orient-portfolio` | RepositoryContext, PortfolioSnapshot, PortfolioPathRef, ProductPath, SourceArtifact, diagnostics | `ScanPortfolio`, `SelectProductPath` | Portfolio Overview, source health, path groups, active/parallel/inactive states | portfolio scan; unresolved refs; path selected |
| `uf-verify-selected-path` | ProductPath, SourceArtifact, SourceBackedClaim, TrustEnvelope, HandoffEligibility | selected-path context, scoped source inventory | Selected Path Detail with source-backed/inferred/partial/warning/blocked labels | selected path source-backed/partial/warning/blocked |
| `uf-inspect-source-provenance` | EvidenceLink, SourceArtifact, SourceBackedClaim, ProvenanceRecord, SourceConfidence | `InspectEvidenceRef`, `InspectProvenance`, claim inspection | Evidence Inspector, Provenance Timeline | evidence/provenance resolved, unresolved, confirmed, review, missing, contradicted |
| `uf-recover-diagnostics` | DiagnosticIssue, affected scopes, TrustLevel, HandoffEligibility | `EvaluateDiagnostics`, trust transitions | Diagnostics Panel | clean/warning/blocked/partial/source-backed degradation and recovery |
| `uf-handoff-resume` | ProductPath, SourceBackedClaim, DiagnosticIssue, HandoffSummary, HandoffEligibility | `GenerateHandoff`, `CopyHandoff` | Handoff Summary and copy/suppression state | requested, clean-copy, warning-copy, blocked, copied, suppressed |
| `uf-explain-boundaries` | ProductPath, BoundaryKind, source rationale, evidence/provenance, diagnostics | `ExplainBoundary`, boundary handoff generation | inactive/promoted/out-of-scope/unsupported/unresolved explanations | active route suppressed; explanatory/boundary handoff prepared |

## Assumptions And Confidence

High confidence:

- ProductPath is the right primary aggregate for selected-path interpretation.
- Portfolio should stay a thin orientation aggregate.
- Parser confidence and source confidence must remain separate.
- Diagnostics need orthogonal severity and affected-level fields.
- Handoff generation is policy output, not independent source truth.

Medium confidence:

- RepositoryContext and PortfolioSnapshot are the right names for read-through context entities.
- One model can cover all six first-read-through branches before key-moments has promoted/pruned individual branches.

Watch item:

- If later key-moments work prunes or narrows branches, this model should be narrowed through modify-back rather than treated as final for pruned paths.

## Physical Concern Deferrals

Deferred to `$spec-interview` or later implementation planning: file watching, parsing implementation, caching, persistence, database schema, storage engine, indexes, migrations, real routes/endpoints/URLs/transports, authentication, authorization, sandbox/permission implementation, deployment, source preview rendering, clipboard/export mechanics, and high-fidelity UI component layout.

Proposed Model Tree YAML

This is the proposed content for design/afps-tracker/model-tree-afps-tracker.yaml.

schema_version: v0.1
mode: product-path
topic: afps-tracker
product_path: research/afps-tracker
status: proposed
flow_tree_ref: design/afps-tracker/flow-tree-afps-tracker.yaml
domain_model_ref: design/afps-tracker/domain-model-afps-tracker.md
alignment_page: alignment/state-model-afps-tracker.html
source_artifacts:
  - design/afps-tracker/_working/state-model-afps-tracker-brief.md
  - design/afps-tracker/flow-tree-afps-tracker.yaml
  - design/afps-tracker/user-flow-afps-tracker.md
  - design/afps-tracker/state-model-afps-tracker/event-modeling.md
  - design/afps-tracker/state-model-afps-tracker/domain-model.md
  - design/afps-tracker/state-model-afps-tracker/state-machine.md
  - design/afps-tracker/state-model-afps-tracker/data-model.md
  - design/afps-tracker/state-model-afps-tracker/contract-map.md
frameworks:
  - id: event-modeling
    status: synthesized
    source: design/afps-tracker/state-model-afps-tracker/event-modeling.md
  - id: domain-model
    status: synthesized
    source: design/afps-tracker/state-model-afps-tracker/domain-model.md
  - id: state-machine
    status: synthesized
    source: design/afps-tracker/state-model-afps-tracker/state-machine.md
  - id: data-model
    status: synthesized
    source: design/afps-tracker/state-model-afps-tracker/data-model.md
  - id: contract-map
    status: synthesized
    source: design/afps-tracker/state-model-afps-tracker/contract-map.md
entities:
  - id: portfolio
    kind: aggregate-root
    attributes: [source_health, active_path_refs, excluded_path_refs, unresolved_refs, parser_confidence, source_confidence]
    relationships: [{to: product-path, cardinality: one-to-many}]
    lifecycle_ref: portfolio-state
    flow_bindings:
      - {flow_node_ref: uf-orient-portfolio, access: displays}
      - {flow_node_ref: uf-recover-diagnostics, access: transitions}
      - {flow_node_ref: uf-explain-boundaries, access: reads}
  - id: repository-context
    kind: entity
    attributes: [repository_ref, scan_started_at, scan_completed_at, scan_state, source_health, warnings]
    relationships: [{to: portfolio-snapshot, cardinality: one-to-zero-or-one}, {to: source-artifact, cardinality: one-to-many}]
    lifecycle_ref: portfolio-state
    flow_bindings:
      - {flow_node_ref: uf-orient-portfolio, access: triggers}
      - {flow_node_ref: uf-recover-diagnostics, access: displays}
  - id: portfolio-snapshot
    kind: entity
    attributes: [snapshot_id, progress_manifest_ref, snapshot_state, active_path_refs, excluded_path_refs, parser_confidence, source_confidence]
    relationships: [{to: portfolio-path-ref, cardinality: one-to-many}, {to: product-path, cardinality: one-to-many}]
    lifecycle_ref: portfolio-state
    flow_bindings:
      - {flow_node_ref: uf-orient-portfolio, access: displays}
      - {flow_node_ref: uf-explain-boundaries, access: reads}
  - id: portfolio-path-ref
    kind: entity
    attributes: [path_ref_id, path_id, scope_path, source_status, resolution_state, boundary_kind, diagnostic_refs]
    relationships: [{to: product-path, cardinality: many-to-zero-or-one}]
    flow_bindings:
      - {flow_node_ref: uf-orient-portfolio, access: displays}
      - {flow_node_ref: uf-recover-diagnostics, access: writes}
      - {flow_node_ref: uf-explain-boundaries, access: reads}
  - id: product-path
    kind: aggregate-root
    attributes: [path_id, label, scope_path, source_status, pipeline_stage, reason, next_skill, revisit_trigger, last_touched, path_state, trust_level, handoff_eligibility, boundary_kind]
    relationships: [{to: source-artifact, cardinality: one-to-many}, {to: source-backed-claim, cardinality: one-to-many}, {to: diagnostic-issue, cardinality: one-to-many}, {to: handoff-summary, cardinality: one-to-many}]
    lifecycle_ref: product-path-state
    flow_bindings:
      - {flow_node_ref: uf-orient-portfolio, access: displays}
      - {flow_node_ref: uf-verify-selected-path, access: writes}
      - {flow_node_ref: uf-recover-diagnostics, access: transitions}
      - {flow_node_ref: uf-handoff-resume, access: reads}
      - {flow_node_ref: uf-explain-boundaries, access: displays}
  - id: source-artifact
    kind: entity
    attributes: [artifact_id, artifact_ref, artifact_kind, source_role, read_status, approval_status, freshness_state, parser_confidence, source_confidence, warnings]
    relationships: [{to: source-backed-claim, cardinality: many-to-many}, {to: provenance-record, cardinality: many-to-many}]
    lifecycle_ref: source-artifact-state
    flow_bindings:
      - {flow_node_ref: uf-verify-selected-path, access: reads}
      - {flow_node_ref: uf-inspect-source-provenance, access: displays}
      - {flow_node_ref: uf-recover-diagnostics, access: transitions}
  - id: source-backed-claim
    kind: entity
    attributes: [claim_id, claim_kind, claim_text, support_status, parser_confidence, source_confidence, trust_level, derived_from, warnings]
    relationships: [{to: evidence-link, cardinality: one-to-many}, {to: diagnostic-issue, cardinality: one-to-many}]
    lifecycle_ref: evidence-link-state
    flow_bindings:
      - {flow_node_ref: uf-verify-selected-path, access: displays}
      - {flow_node_ref: uf-inspect-source-provenance, access: reads}
      - {flow_node_ref: uf-recover-diagnostics, access: reads}
      - {flow_node_ref: uf-handoff-resume, access: reads}
  - id: evidence-link
    kind: entity
    attributes: [evidence_link_id, claim_id, evidence_ref, resolved_ref, resolution_state, support_status, read_status, source_hint, warnings]
    relationships: [{to: source-artifact, cardinality: many-to-zero-or-one}]
    lifecycle_ref: evidence-link-state
    flow_bindings:
      - {flow_node_ref: uf-inspect-source-provenance, access: triggers}
      - {flow_node_ref: uf-recover-diagnostics, access: transitions}
  - id: provenance-record
    kind: entity
    attributes: [provenance_id, provenance_ref, provenance_kind, approval_state, decision_summary, canonical_target, archive_refs, confidence, warnings]
    relationships: [{to: source-artifact, cardinality: many-to-many}]
    lifecycle_ref: provenance-record-state
    flow_bindings:
      - {flow_node_ref: uf-inspect-source-provenance, access: displays}
      - {flow_node_ref: uf-recover-diagnostics, access: reads}
      - {flow_node_ref: uf-handoff-resume, access: reads}
  - id: diagnostic-issue
    kind: entity
    attributes: [issue_id, issue_kind, severity, level, state, affected_refs, affected_claims, affected_paths, handoff_impact, recommended_manual_check]
    relationships: [{to: product-path, cardinality: many-to-one}, {to: source-backed-claim, cardinality: many-to-one}, {to: handoff-summary, cardinality: many-to-many}]
    lifecycle_ref: diagnostic-issue-state
    flow_bindings:
      - {flow_node_ref: uf-recover-diagnostics, access: writes}
      - {flow_node_ref: uf-orient-portfolio, access: displays}
      - {flow_node_ref: uf-handoff-resume, access: reads}
  - id: handoff-summary
    kind: entity
    attributes: [summary_id, handoff_type, copy_state, confidence, next_skill, branch_state_explanation, handoff_boundary, included_evidence_refs, included_provenance_refs, included_diagnostic_refs, blocked_reasons]
    relationships: [{to: product-path, cardinality: many-to-one}, {to: diagnostic-issue, cardinality: many-to-many}]
    lifecycle_ref: handoff-summary-state
    flow_bindings:
      - {flow_node_ref: uf-handoff-resume, access: writes}
      - {flow_node_ref: uf-explain-boundaries, access: displays}
value_objects:
  - {id: artifact-ref, fields: [path, section_hint, artifact_kind, source_role]}
  - {id: evidence-ref, fields: [ref, resolved_ref, claim_id, support_status]}
  - {id: path-state, values: [active, parallel-active, archived, deferred, revisit-candidate, promoted, out-of-scope, unresolved, partial, warning, blocked, source-backed, selected]}
  - {id: trust-level, values: [clean, warning, blocked, partial, inferred, unsupported, contradicted, source-backed, explanatory, out-of-scope]}
  - {id: parser-confidence, values: [high, medium, low, unknown]}
  - {id: source-confidence, values: [confirmed, partial, review-only, unsupported, contradicted, missing, unknown]}
  - {id: handoff-eligibility, values: [clean-copy, warning-copy, blocked, explanatory, promoted-boundary, out-of-scope, unavailable]}
  - {id: boundary-kind, values: [inactive, archived, deferred, revisit-candidate, promoted, out-of-scope, unsupported, unresolved]}
state_machines:
  - id: portfolio-state
    subject: Portfolio
    states:
      - {id: unscanned, maps_to_ui_state: empty initial portfolio frame}
      - {id: scanning, maps_to_ui_state: loading portfolio overview}
      - {id: no-afps-state, maps_to_ui_state: empty or no-manifest state}
      - {id: manifest-malformed, maps_to_ui_state: blocking parse diagnostic}
      - {id: paths-discovered, maps_to_ui_state: grouped portfolio rows}
      - {id: partial, maps_to_ui_state: visible warning or partial badges}
      - {id: source-backed, maps_to_ui_state: clean portfolio overview}
      - {id: blocked, maps_to_ui_state: blocking portfolio diagnostic}
    transitions:
      - {from: unscanned, event: ScanPortfolio, to: scanning}
      - {from: scanning, event: ProgressManifestMissing, to: no-afps-state}
      - {from: scanning, event: ProgressManifestMalformed, to: manifest-malformed}
      - {from: scanning, event: ProductPathRecordDiscovered, to: paths-discovered}
      - {from: paths-discovered, event: DiagnosticIssueClassified, to: source-backed}
      - {from: paths-discovered, event: ActivePathReferenceUnresolved, to: partial}
      - {from: partial, event: DiagnosticIssueClassified, to: blocked}
  - id: product-path-state
    subject: ProductPath
    states:
      - {id: undiscovered, maps_to_ui_state: unresolved active ref or absent path}
      - {id: discovered, maps_to_ui_state: portfolio row}
      - {id: selected, maps_to_ui_state: product-path detail loading frame}
      - {id: source-inventorying, maps_to_ui_state: detail surface source checks}
      - {id: source-backed, maps_to_ui_state: clean selected-path detail}
      - {id: partial, maps_to_ui_state: partial badges and unresolved refs}
      - {id: warning, maps_to_ui_state: warning detail and handoff caveats}
      - {id: blocked, maps_to_ui_state: blocked detail and diagnostics}
      - {id: inactive, maps_to_ui_state: inactive path explanation}
      - {id: promoted-boundary, maps_to_ui_state: promoted boundary explanation}
      - {id: out-of-scope, maps_to_ui_state: out-of-scope explanation}
    transitions:
      - {from: undiscovered, event: ProductPathRecordDiscovered, to: discovered}
      - {from: discovered, event: ProductPathSelected, to: selected}
      - {from: selected, event: ScopedSourceInventoryStarted, to: source-inventorying}
      - {from: source-inventorying, event: ClaimSupportEvaluated, to: source-backed}
      - {from: source-inventorying, event: EvidenceRefUnresolved, to: partial}
      - {from: source-backed, event: DiagnosticIssueRaised, to: warning}
      - {from: warning, event: DiagnosticIssueClassified, to: blocked}
      - {from: discovered, event: ProductPathRecordExcluded, to: inactive}
      - {from: discovered, event: PromotedBoundaryDetected, to: promoted-boundary}
  - id: source-artifact-state
    subject: SourceArtifact
    states: [referenced, resolving, found, parsed, confirmed, review-only, amended, archived, missing, unreadable, malformed, stale, unsupported]
    transitions: [{from: referenced, event: EvidenceRefResolutionStarted, to: resolving}, {from: resolving, event: EvidenceRefResolved, to: found}, {from: found, event: ProgressManifestParsed, to: parsed}, {from: parsed, event: ProvenanceRecordConfirmed, to: confirmed}]
  - id: evidence-link-state
    subject: EvidenceLink
    states: [unresolved, resolving, resolved, supports-claim, partially-supports-claim, contradicts-claim, inaccessible]
    transitions: [{from: unresolved, event: InspectEvidenceRef, to: resolving}, {from: resolving, event: EvidenceRefResolved, to: resolved}, {from: resolved, event: ClaimSupportEvaluated, to: supports-claim}]
  - id: provenance-record-state
    subject: ProvenanceRecord
    states: [missing, discovered, review, confirmed, amended, archived, partial, contradicted]
    transitions: [{from: missing, event: ProvenanceRecordDiscovered, to: discovered}, {from: discovered, event: ProvenanceRecordConfirmed, to: confirmed}, {from: discovered, event: ProvenanceRecordReviewOnly, to: review}]
  - id: diagnostic-issue-state
    subject: DiagnosticIssue
    states: [none, raised, classified, warning, blocked, partial, source-level, claim-level, path-level, portfolio-level, handoff-level, resolved-by-source-review]
    transitions: [{from: none, event: DiagnosticIssueRaised, to: raised}, {from: raised, event: DiagnosticIssueClassified, to: classified}, {from: classified, event: severity-policy, to: warning}, {from: classified, event: severity-policy, to: blocked}]
  - id: handoff-summary-state
    subject: HandoffSummary
    states: [unavailable, requested, clean-copy, warning-copy, blocked, explanatory, promoted-boundary, out-of-scope, copied, suppressed]
    transitions: [{from: unavailable, event: GenerateHandoff, to: requested}, {from: requested, event: CleanCopyPrepared, to: clean-copy}, {from: requested, event: WarningCopyPrepared, to: warning-copy}, {from: requested, event: HandoffBlocked, to: blocked}, {from: clean-copy, event: CopyHandoff, to: copied}]
events:
  - {id: repository-scan-started, flow_bindings: [{flow_node_ref: uf-orient-portfolio, access: triggers}]}
  - {id: progress-manifest-parsed, flow_bindings: [{flow_node_ref: uf-orient-portfolio, access: reads}]}
  - {id: product-path-selected, flow_bindings: [{flow_node_ref: uf-verify-selected-path, access: writes}]}
  - {id: evidence-ref-resolved, flow_bindings: [{flow_node_ref: uf-inspect-source-provenance, access: displays}]}
  - {id: provenance-record-confirmed, flow_bindings: [{flow_node_ref: uf-inspect-source-provenance, access: displays}]}
  - {id: diagnostic-issue-classified, flow_bindings: [{flow_node_ref: uf-recover-diagnostics, access: transitions}]}
  - {id: handoff-summary-prepared, flow_bindings: [{flow_node_ref: uf-handoff-resume, access: displays}]}
  - {id: promoted-boundary-detected, flow_bindings: [{flow_node_ref: uf-explain-boundaries, access: displays}]}
commands:
  - {id: scan-portfolio, flow_bindings: [{flow_node_ref: uf-orient-portfolio, access: triggers}]}
  - {id: select-product-path, flow_bindings: [{flow_node_ref: uf-verify-selected-path, access: writes}]}
  - {id: evaluate-diagnostics, flow_bindings: [{flow_node_ref: uf-recover-diagnostics, access: writes}]}
  - {id: generate-handoff, flow_bindings: [{flow_node_ref: uf-handoff-resume, access: triggers}, {flow_node_ref: uf-explain-boundaries, access: triggers}]}
  - {id: copy-handoff, flow_bindings: [{flow_node_ref: uf-handoff-resume, access: writes}]}
read_models:
  - {id: portfolio-overview, flow_bindings: [{flow_node_ref: uf-orient-portfolio, access: displays}]}
  - {id: selected-path-detail, flow_bindings: [{flow_node_ref: uf-verify-selected-path, access: displays}]}
  - {id: evidence-inspector, flow_bindings: [{flow_node_ref: uf-inspect-source-provenance, access: displays}]}
  - {id: provenance-timeline, flow_bindings: [{flow_node_ref: uf-inspect-source-provenance, access: displays}]}
  - {id: diagnostics-panel, flow_bindings: [{flow_node_ref: uf-recover-diagnostics, access: displays}]}
  - {id: handoff-summary, flow_bindings: [{flow_node_ref: uf-handoff-resume, access: displays}, {flow_node_ref: uf-explain-boundaries, access: displays}]}
policies:
  - {id: source-truth-policy, flow_bindings: [{flow_node_ref: uf-verify-selected-path, access: reads}, {flow_node_ref: uf-inspect-source-provenance, access: reads}]}
  - {id: active-path-resolution-policy, flow_bindings: [{flow_node_ref: uf-orient-portfolio, access: reads}, {flow_node_ref: uf-recover-diagnostics, access: transitions}]}
  - {id: diagnostic-severity-policy, flow_bindings: [{flow_node_ref: uf-recover-diagnostics, access: transitions}]}
  - {id: handoff-eligibility-policy, flow_bindings: [{flow_node_ref: uf-handoff-resume, access: displays}, {flow_node_ref: uf-explain-boundaries, access: displays}]}
  - {id: boundary-preservation-policy, flow_bindings: [{flow_node_ref: uf-explain-boundaries, access: displays}]}
contracts:
  - id: scan-portfolio-contract
    kind: command
    request_shape: {repository_context: RepositoryContextInput, include_inactive: boolean, include_diagnostics: boolean, source_refs: ArtifactRef[]}
    response_shape: {scan_state: string, repository_ref: ArtifactRef, portfolio_snapshot_id: string, source_health: TrustEnvelope, path_counts: object, active_path_refs: PortfolioPathRef[], excluded_path_refs: PortfolioPathRef[], unresolved_path_refs: PortfolioPathRef[], diagnostics: DiagnosticRef[]}
    error_shape: [no-afps-state, progress-manifest-missing, progress-manifest-malformed, permission-denied, scan-partial, source-unreadable]
    flow_bindings: [{flow_node_ref: uf-orient-portfolio, access: triggers}]
  - id: get-selected-path-detail-contract
    kind: query
    request_shape: {selector: ProductPathSelector, include_claims: boolean, include_refs: boolean, include_diagnostics: boolean}
    response_shape: {path_id: string, label: string, scope_path: ArtifactRef, source_status: PathState, path_state: PathState, pipeline_stage: string, reason: string, next_skill: string, trust: TrustEnvelope, claims: SourceBackedClaim[], diagnostics: DiagnosticRef[], handoff_eligibility: HandoffEligibility}
    error_shape: [path-not-selected, path-not-found, source-artifact-missing, path-detail-partial, path-detail-blocked, path-state-contradicted]
    flow_bindings: [{flow_node_ref: uf-verify-selected-path, access: reads}]
  - id: inspect-evidence-ref-contract
    kind: query
    request_shape: {claim_ref: ClaimRef, evidence_ref: EvidenceRef, path_id: string, source_hint: string, preview_requested: boolean}
    response_shape: {claim_id: string, evidence_link_id: string, resolved_ref: ArtifactRef, support_status: string, trust: TrustEnvelope, diagnostics: DiagnosticRef[]}
    error_shape: [claim-not-found, evidence-ref-missing, evidence-ref-unresolved, source-preview-unavailable, evidence-inaccessible, claim-contradicted]
    flow_bindings: [{flow_node_ref: uf-inspect-source-provenance, access: displays}]
  - id: inspect-provenance-contract
    kind: query
    request_shape: {path_id: string, claim_ref: ClaimRef, artifact_ref: ArtifactRef, include_archives: boolean, include_review_records: boolean}
    response_shape: {records: ProvenanceRecord[], approval_state: string, confirmed_records: ProvenanceRecord[], review_only_records: ProvenanceRecord[], archive_refs: ArtifactRef[], confidence: SourceConfidence, warnings: string[], diagnostics: DiagnosticRef[]}
    error_shape: [provenance-missing, provenance-review-only, provenance-contradicted, archive-ref-missing, canonical-target-unreadable]
    flow_bindings: [{flow_node_ref: uf-inspect-source-provenance, access: displays}]
  - id: evaluate-diagnostics-contract
    kind: command
    request_shape: {repository_ref: ArtifactRef, path_id: string, claim_refs: ClaimRef[], artifact_refs: ArtifactRef[], evaluation_reason: string, prior_diagnostic_refs: DiagnosticRef[]}
    response_shape: {diagnostics: DiagnosticRef[], trust_changes: object[], handoff_eligibility: HandoffEligibility, affected_read_models: string[], manual_checks: string[], warnings_to_preserve: string[], blocked_reasons: string[]}
    error_shape: [diagnostic-source-missing, diagnostic-scope-ambiguous, cannot-classify-issue, source-review-required]
    flow_bindings: [{flow_node_ref: uf-recover-diagnostics, access: writes}]
  - id: generate-handoff-contract
    kind: command
    request_shape: {selector: ProductPathSelector, handoff_intent: string, detail_level: string, include_refs: boolean, include_diagnostics: boolean}
    response_shape: {summary_id: string, handoff_type: string, handoff_state: string, path_id: string, next_skill: string, branch_state_explanation: string, confidence: TrustEnvelope, evidence_refs: EvidenceRef[], provenance_refs: ProvenanceRecord[], warnings: string[], blocked_reasons: string[], boundary: HandoffBoundary, copy_allowed: boolean, normal_next_command_suppressed: boolean}
    error_shape: [handoff-unavailable, blocking-diagnostics-present, next-skill-unsupported, boundary-explanation-required, source-support-insufficient, out-of-scope-request]
    flow_bindings: [{flow_node_ref: uf-handoff-resume, access: triggers}, {flow_node_ref: uf-explain-boundaries, access: triggers}]
  - id: copy-handoff-contract
    kind: command
    request_shape: {summary_id: string, copy_intent: string, acknowledged_warnings: string[], requested_format: string}
    response_shape: {copy_state: string, summary_id: string, warnings_preserved: string[], suppression_reason: string, copied_payload_shape: string, diagnostic_refs: DiagnosticRef[], boundary: HandoffBoundary}
    error_shape: [summary-not-found, warnings-not-preserved, copy-blocked-by-diagnostics, next-command-suppressed, copy-format-unsupported]
    flow_bindings: [{flow_node_ref: uf-handoff-resume, access: writes}]
  - id: explain-boundary-contract
    kind: query
    request_shape: {selector: ProductPathSelector, boundary_kind: BoundaryKind, requested_by: string, include_refs: boolean}
    response_shape: {path_id: string, boundary_kind: BoundaryKind, source_status: PathState, branch_state_explanation: string, normal_route_suppressed: boolean, suppression_reason: string, promoted_boundary: boolean, handoff_boundary: HandoffBoundary, evidence_refs: EvidenceRef[], provenance_refs: ProvenanceRecord[], warnings: string[], diagnostics: DiagnosticRef[], next_step_visibility: string}
    error_shape: [boundary-not-applicable, boundary-source-missing, promoted-boundary-unsupported, out-of-scope-request, inactive-state-contradicted]
    flow_bindings: [{flow_node_ref: uf-explain-boundaries, access: reads}]

Flow Bindings

Flow nodePrimary read modelCore elementsTrust behavior
uf-orient-portfolioPortfolio OverviewRepositoryContext, PortfolioSnapshot, PortfolioPathRef, ProductPath, DiagnosticIssueShows active, parallel, inactive, excluded, unresolved, partial, warning, and blocked states.
uf-verify-selected-pathSelected Path DetailProductPath, SourceArtifact, SourceBackedClaim, EvidenceLink, ProvenanceRecordSeparates source-backed, inferred, partial, unsupported, contradicted, and blocked claims.
uf-inspect-source-provenanceEvidence Inspector and Provenance TimelineEvidenceLink, SourceArtifact, SourceBackedClaim, ProvenanceRecordPreserves claim IDs, support status, parser confidence, source confidence, and provenance caveats.
uf-recover-diagnosticsDiagnostics PanelDiagnosticIssue, TrustLevel, HandoffEligibility, affected refs/claims/pathsDegrades trust at narrowest scope and names handoff impact.
uf-handoff-resumeHandoff SummaryHandoffSummary, ProductPath, SourceBackedClaim, EvidenceLink, ProvenanceRecord, DiagnosticIssueClean copy only when source-backed; warning copy preserves caveats; blocked copy names suppression reasons.
uf-explain-boundariesBoundary ExplanationProductPath, BoundaryKind, HandoffSummary, diagnostics, evidence/provenance refsSuppresses normal routing for inactive, promoted, out-of-scope, unresolved, unsupported, or contradicted states.

Visual Model

Logical ERD

RepositoryContext PortfolioSnapshot PortfolioPathRef ProductPath SourceArtifact SourceBackedClaim EvidenceLink ProvenanceRecord DiagnosticIssue HandoffSummary
SourceRelationshipTarget
RepositoryContextone to zero-or-onePortfolioSnapshot
PortfolioSnapshotone to manyPortfolioPathRef and ProductPath
ProductPathone to manySourceArtifact, SourceBackedClaim, ProvenanceRecord, DiagnosticIssue, HandoffSummary
SourceBackedClaimone to manyEvidenceLink and DiagnosticIssue

Product Path Lifecycle

undiscovered discovered selected source-inventorying source-backed warning blocked inactive promoted-boundary out-of-scope
TransitionTriggerUI state
undiscovered to discoveredProductPathRecordDiscoveredPortfolio row
discovered to selectedProductPathSelectedDetail loading frame
source-inventorying to source-backed/warning/blockedClaim support and diagnosticsClean, warning, or blocked detail
discovered to inactive/promoted/out-of-scopeBoundary policyExplanation instead of normal routing

Proposed File Changes After Approval

PathChangeApproval dependency
design/afps-tracker/domain-model-afps-tracker.mdNew canonical domain model Markdown from the proposed content above.Domain model approval gate.
design/afps-tracker/model-tree-afps-tracker.yamlNew canonical model-tree manifest from the proposed YAML above.Model-tree approval gate.
design/afps-tracker/flow-tree-afps-tracker.yamlAdd model_tree_ref and attach branches[].model_ref to the six covered flow branches. Do not touch route or duplicate flow_bindings.Flow binding approval gate.
research/afps-tracker/glossary.mdAppend only glossary terms approved in the glossary gate.Glossary gate.
docs/history/archive/YYYY-MM-DD/HHMMSS/...Archive the brief and framework intermediates at canonical write time.Final approval.
alignment/state-model-afps-tracker.htmlConvert this page from review to confirmed after approved YAML is consumed and canonical artifacts are written.Final approval.

Approval Gates

Domain Model Approval

Approve the proposed logical domain model Markdown?

Model Tree Manifest Approval

Approve the proposed model-tree YAML shape and flow bindings?

Flow Binding Approval

Approve attaching this model to all six covered first-read-through branches and writing the optional top-level model_tree_ref pointer?

Glossary Additions Gate

Choose whether to append the proposed model terms to the AFPS Tracker glossary.

Compile Responses

Use this after selecting gate answers. Partial feedback is allowed; approval becomes ready only when every required gate is answered without modification or clarification requests.