@kontourai/flow-agents 2.3.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/CODEOWNERS +16 -0
- package/.github/workflows/ci.yml +44 -0
- package/.github/workflows/trust-reconcile.yml +62 -4
- package/AGENTS.md +4 -4
- package/CHANGELOG.md +62 -0
- package/CONTEXT.md +35 -0
- package/README.md +9 -3
- package/agents/dev.json +1 -1
- package/agents/tool-code-reviewer.json +1 -1
- package/agents/tool-planner.json +3 -3
- package/agents/tool-verifier.json +3 -3
- package/build/src/cli/assignment-provider.d.ts +1 -0
- package/build/src/cli/assignment-provider.js +748 -0
- package/build/src/cli/console-learning-projection.js +3 -2
- package/build/src/cli/effective-assignment-provider-settings.d.ts +1 -0
- package/build/src/cli/effective-assignment-provider-settings.js +125 -0
- package/build/src/cli/init.js +104 -21
- package/build/src/cli/kit.js +37 -6
- package/build/src/cli/pull-work-provider.js +1 -1
- package/build/src/cli/usage-feedback.js +3 -3
- package/build/src/cli/validate-hook-influence.js +1 -0
- package/build/src/cli/validate-workflow-artifacts.js +27 -7
- package/build/src/cli/workflow-artifact-cleanup-audit.js +36 -2
- package/build/src/cli/workflow-sidecar.d.ts +14 -7
- package/build/src/cli/workflow-sidecar.js +938 -168
- package/build/src/cli.js +6 -0
- package/build/src/flow-kit/validate.d.ts +23 -0
- package/build/src/flow-kit/validate.js +67 -1
- package/build/src/index.d.ts +1 -1
- package/build/src/index.js +1 -1
- package/build/src/lib/flow-resolver.d.ts +6 -4
- package/build/src/lib/flow-resolver.js +125 -58
- package/build/src/lib/local-artifact-root.d.ts +14 -2
- package/build/src/lib/local-artifact-root.js +22 -5
- package/build/src/lib/workflow-learning-projection.js +2 -2
- package/build/src/runtime-adapters.d.ts +12 -0
- package/build/src/runtime-adapters.js +56 -16
- package/build/src/tools/build-universal-bundles.js +49 -16
- package/build/src/tools/generate-context-map.js +10 -8
- package/build/src/tools/validate-source-tree.js +24 -1
- package/console.telemetry.json +22 -0
- package/context/contracts/artifact-contract.md +40 -7
- package/context/contracts/assignment-provider-contract.md +239 -0
- package/context/contracts/builder-kit-workflow-state-contract.md +5 -2
- package/context/contracts/decision-registry-contract.md +265 -0
- package/context/contracts/delivery-contract.md +3 -1
- package/context/contracts/execution-contract.md +25 -0
- package/context/contracts/governance-adapter-contract.md +2 -0
- package/context/contracts/knowledge-store-contract.md +197 -0
- package/context/contracts/planning-contract.md +4 -1
- package/context/contracts/review-contract.md +7 -3
- package/context/contracts/sandbox-policy.md +2 -0
- package/context/contracts/standing-directives.md +13 -0
- package/context/contracts/verification-contract.md +11 -1
- package/context/contracts/work-item-contract.md +3 -1
- package/context/deferred/parallelization.md +1 -1
- package/context/gate-awareness.md +4 -4
- package/context/scripts/git-status.sh +2 -2
- package/context/scripts/hooks/config-protection.js +502 -2
- package/context/scripts/hooks/lib/config-protection-remedies.js +69 -0
- package/context/scripts/hooks/run-hook.js +14 -1
- package/context/scripts/hooks/stop-goal-fit.js +1140 -99
- package/context/scripts/hooks/workflow-steering.js +212 -6
- package/context/settings/assignment-provider-settings.json +33 -0
- package/docs/adr/0007-flow-skill-kit-tool-boundary.md +2 -0
- package/docs/adr/0015-flow-flow-agents-boundary-reconciliation.md +35 -0
- package/docs/adr/0019-kit-dependency-ownership.md +62 -0
- package/docs/adr/0020-trust-reconcile-manifest-and-claim-classification.md +290 -0
- package/docs/adr/0021-assignment-leases-and-stale-claim-takeover.md +221 -0
- package/docs/adr/0022-fail-closed-delivery-reconciliation-with-governed-exemptions.md +463 -0
- package/docs/agent-system-guidebook.md +3 -3
- package/docs/agent-usage-feedback-loop.md +6 -6
- package/docs/context-map.md +10 -7
- package/docs/decisions/decision-records.md +57 -0
- package/docs/decisions/index.md +17 -0
- package/docs/decisions/knowledge-store-provider.md +51 -0
- package/docs/decisions/model-routing.md +63 -0
- package/docs/decisions/promotion-gate.md +52 -0
- package/docs/decisions/standing-directives.md +66 -0
- package/docs/developer-architecture.md +1 -1
- package/docs/fixture-ownership.md +4 -0
- package/docs/flow-kit-repository-contract.md +5 -5
- package/docs/getting-started.md +12 -2
- package/docs/integrations/harness-install.md +2 -1
- package/docs/kit-authoring-guide.md +64 -5
- package/docs/knowledge-kit.md +5 -1
- package/docs/learnings/2026-07-improvement-program.md +203 -0
- package/docs/migrations.md +6 -5
- package/docs/north-star.md +2 -2
- package/docs/operating-layers.md +4 -3
- package/docs/repository-structure.md +5 -5
- package/docs/skills-map.md +8 -8
- package/docs/spec/runtime-hook-surface.md +19 -15
- package/docs/spikes/graph-provider-2026-07.md +155 -0
- package/docs/standards-register.md +7 -7
- package/docs/trust-anchor-adoption.md +105 -4
- package/docs/work-item-adapters.md +1 -1
- package/docs/workflow-artifact-lifecycle.md +72 -9
- package/docs/workflow-eval-strategy.md +3 -3
- package/docs/workflow-shared-contracts.md +3 -2
- package/docs/workflow-usage-guide.md +260 -21
- package/evals/acceptance/DEMO-false-completion.md +20 -11
- package/evals/acceptance/prove-capture-teeth-declared.sh +15 -15
- package/evals/acceptance/prove-capture-teeth.sh +11 -11
- package/evals/acceptance/test_kiro_harness.sh +1 -1
- package/evals/ci/antigaming-suite.sh +5 -0
- package/evals/ci/run-baseline.sh +71 -1
- package/evals/fixtures/assignment-provider/actor-a.json +6 -0
- package/evals/fixtures/assignment-provider/actor-b.json +6 -0
- package/evals/fixtures/assignment-provider/github-issue-claimed.json +27 -0
- package/evals/fixtures/assignment-provider/github-issue-unassigned.json +7 -0
- package/evals/fixtures/assignment-provider/liveness-fresh.json +9 -0
- package/evals/fixtures/assignment-provider/liveness-stale.json +9 -0
- package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/flows/review.flow.json +26 -0
- package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/kit.json +13 -0
- package/evals/fixtures/flow-kit-repository/valid-with-dependency/flows/review.flow.json +26 -0
- package/evals/fixtures/flow-kit-repository/valid-with-dependency/kit.json +13 -0
- package/evals/fixtures/hook-influence/cases.json +32 -0
- package/evals/fixtures/pull-work-provider/github-issues.json +6 -6
- package/evals/fixtures/trust-reconcile-exploits/fabricated-attestation.json +59 -0
- package/evals/fixtures/trust-reconcile-exploits/no-label-bypass.json +36 -0
- package/evals/fixtures/trust-reconcile-exploits/skip-assumed-bypass.json +59 -0
- package/evals/fixtures/trust-reconcile-exploits/status-misassertion.json +48 -0
- package/evals/fixtures/trust-reconcile-exploits/waived-command-check.json +44 -0
- package/evals/fixtures/trust-reconcile-mixed-bundle/mixed-bundle.json +159 -0
- package/evals/fixtures/trust-reconcile-ws3/ws3-bundle.json +920 -0
- package/evals/integration/test_actor_identity.sh +254 -0
- package/evals/integration/test_assignment_provider_github.sh +318 -0
- package/evals/integration/test_assignment_provider_local_file.sh +222 -0
- package/evals/integration/test_builder_step_producers.sh +33 -23
- package/evals/integration/test_bundle_install.sh +22 -16
- package/evals/integration/test_bundle_lifecycle.sh +11 -11
- package/evals/integration/test_captured_fail_reconciliation.sh +50 -50
- package/evals/integration/test_checkpoint_signing.sh +43 -0
- package/evals/integration/test_claim_lookup.sh +4 -4
- package/evals/integration/test_codex_hook_resolution.sh +114 -0
- package/evals/integration/test_command_log_concurrency.sh +8 -8
- package/evals/integration/test_command_log_fork_classification.sh +3 -3
- package/evals/integration/test_command_log_integrity.sh +16 -16
- package/evals/integration/test_console_learning_projection.sh +1 -1
- package/evals/integration/test_critique_supersession_roundtrip.sh +182 -0
- package/evals/integration/test_dual_emit_flow_step.sh +145 -0
- package/evals/integration/test_enforcer_expects_driven.sh +12 -12
- package/evals/integration/test_evidence_capture_hook.sh +14 -13
- package/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/evals/integration/test_flow_agents_statusline.sh +2 -2
- package/evals/integration/test_flow_kit_install_git.sh +52 -0
- package/evals/integration/test_flow_kit_repository.sh +2 -0
- package/evals/integration/test_flowdef_session_activation.sh +6 -6
- package/evals/integration/test_flowdef_union_floor_regression.sh +429 -0
- package/evals/integration/test_gate_bypass_chain.sh +52 -40
- package/evals/integration/test_gate_lockdown.sh +97 -73
- package/evals/integration/test_gate_review_inquiry_records.sh +3 -3
- package/evals/integration/test_goal_fit_escape_hatch.sh +10 -10
- package/evals/integration/test_goal_fit_ghost_session.sh +104 -0
- package/evals/integration/test_goal_fit_hook.sh +32 -32
- package/evals/integration/test_goal_fit_rederive.sh +9 -9
- package/evals/integration/test_hook_category_behaviors.sh +103 -0
- package/evals/integration/test_hook_influence_cases.sh +1 -0
- package/evals/integration/test_install_merge.sh +262 -1
- package/evals/integration/test_kit_identity_trust.sh +6 -6
- package/evals/integration/test_liveness_conflict_injection.sh +587 -0
- package/evals/integration/test_liveness_heartbeat.sh +677 -0
- package/evals/integration/test_liveness_verdict.sh +394 -0
- package/evals/integration/test_local_flow_kit_install.sh +15 -0
- package/evals/integration/test_phase_map_and_gate_claim.sh +63 -11
- package/evals/integration/test_promote_gate.sh +178 -0
- package/evals/integration/test_publish_delivery.sh +23 -6
- package/evals/integration/test_pull_work_assignment_join.sh +132 -0
- package/evals/integration/test_pull_work_liveness_preflight.sh +394 -0
- package/evals/integration/test_pull_work_provider.sh +2 -2
- package/evals/integration/test_reconcile_soundness.sh +37 -13
- package/evals/integration/test_resolvefirststep_security.sh +22 -0
- package/evals/integration/test_runtime_adapter_activation.sh +87 -18
- package/evals/integration/test_session_resume_roundtrip.sh +147 -0
- package/evals/integration/test_sidecar_field_preservation.sh +249 -0
- package/evals/integration/test_trust_reconcile.sh +11 -10
- package/evals/integration/test_trust_reconcile_manifest.sh +79 -0
- package/evals/integration/test_trust_reconcile_mixed_bundle.sh +96 -0
- package/evals/integration/test_trust_reconcile_negatives.sh +759 -0
- package/evals/integration/test_usage_feedback_global.sh +5 -5
- package/evals/integration/test_validate_artifacts_portability.sh +60 -0
- package/evals/integration/test_verify_cli.sh +2 -2
- package/evals/integration/test_veritas_governance_kit.sh +117 -0
- package/evals/integration/test_workflow_artifact_cleanup_audit.sh +26 -1
- package/evals/integration/test_workflow_artifacts.sh +33 -0
- package/evals/integration/test_workflow_sidecar_writer.sh +802 -74
- package/evals/integration/test_workflow_steering_hook.sh +175 -5
- package/evals/lib/codex-provider.sh +1 -1
- package/evals/lib/node.sh +19 -1
- package/evals/run.sh +32 -0
- package/evals/static/test_decisions.sh +150 -0
- package/evals/static/test_flowdef_codeowners_coverage.sh +62 -0
- package/evals/static/test_knowledge_providers.sh +23 -0
- package/evals/static/test_package.sh +19 -10
- package/evals/static/test_universal_bundles.sh +48 -3
- package/evals/static/test_workflow_skills.sh +41 -8
- package/kits/builder/flows/build.flow.json +3 -74
- package/kits/builder/flows/publish-learn.flow.json +90 -0
- package/kits/builder/kit.json +11 -0
- package/kits/builder/skills/builder-shape/SKILL.md +1 -1
- package/kits/builder/skills/deliver/SKILL.md +32 -11
- package/kits/builder/skills/design-probe/SKILL.md +4 -4
- package/kits/builder/skills/evidence-gate/SKILL.md +26 -1
- package/kits/builder/skills/execute-plan/SKILL.md +2 -2
- package/kits/builder/skills/fix-bug/SKILL.md +2 -0
- package/kits/builder/skills/gate-review/SKILL.md +6 -6
- package/kits/builder/skills/idea-to-backlog/SKILL.md +1 -1
- package/kits/builder/skills/learning-review/SKILL.md +7 -7
- package/kits/builder/skills/pickup-probe/SKILL.md +5 -4
- package/kits/builder/skills/plan-work/SKILL.md +27 -5
- package/kits/builder/skills/pull-work/SKILL.md +148 -5
- package/kits/builder/skills/release-readiness/SKILL.md +4 -4
- package/kits/builder/skills/review-work/SKILL.md +24 -1
- package/kits/builder/skills/tdd-workflow/SKILL.md +2 -0
- package/kits/builder/skills/verify-work/SKILL.md +8 -1
- package/kits/catalog.json +6 -0
- package/kits/knowledge/kit.json +35 -0
- package/kits/knowledge/providers/conformance/fixtures/git-repo/CONTEXT.md +12 -0
- package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/old-sprocket-shape.md +13 -0
- package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/sprocket-shape.md +14 -0
- package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/decisions/widget-format.md +14 -0
- package/kits/knowledge/providers/conformance/fixtures/git-repo/docs/learnings/fixture-learning.md +7 -0
- package/kits/knowledge/providers/conformance/fixtures/work-item/issues.json +30 -0
- package/kits/knowledge/providers/conformance/suite.test.js +125 -0
- package/kits/knowledge/providers/git-repo/index.js +236 -0
- package/kits/knowledge/providers/health/health-pass.test.js +99 -0
- package/kits/knowledge/providers/health/index.js +153 -0
- package/kits/knowledge/providers/index.js +24 -0
- package/kits/knowledge/providers/lib/model.js +91 -0
- package/kits/knowledge/providers/lib/schema-validate.js +119 -0
- package/kits/knowledge/providers/markdown-vault/index.js +169 -0
- package/kits/knowledge/providers/work-item/index.js +204 -0
- package/kits/veritas-governance/adapter/readiness-to-trust-bundle.mjs +178 -0
- package/kits/veritas-governance/docs/README.md +75 -0
- package/kits/veritas-governance/fixtures/readiness/not-ready.readiness-report.json +4645 -0
- package/kits/veritas-governance/fixtures/readiness/ready.readiness-report.json +4403 -0
- package/kits/veritas-governance/flows/readiness-check.flow.json +35 -0
- package/kits/veritas-governance/kit.json +16 -0
- package/package.json +11 -5
- package/packaging/README.md +2 -2
- package/packaging/conformance/fixtures/config-protection--allow-read-state-json.json +20 -0
- package/packaging/conformance/fixtures/config-protection--block-write-state-json.json +20 -0
- package/packaging/conformance/fixtures/stop-goal-fit--block-bundle-disputed-claim.json +1 -1
- package/packaging/conformance/fixtures/stop-goal-fit--block-capture-contradicts-claimed-pass.json +1 -1
- package/packaging/manifest.json +9 -10
- package/schemas/assignment-provider-settings.schema.json +125 -0
- package/schemas/decision-record.schema.json +109 -0
- package/schemas/knowledge/edge.schema.json +54 -0
- package/schemas/knowledge/health-report.schema.json +45 -0
- package/schemas/knowledge/node.schema.json +49 -0
- package/schemas/knowledge/proposal.schema.json +53 -0
- package/schemas/workflow-evidence.schema.json +1 -1
- package/schemas/workflow-state.schema.json +5 -0
- package/scripts/README.md +8 -3
- package/scripts/check-content-boundary.cjs +1 -1
- package/scripts/check-decisions.cjs +356 -0
- package/scripts/ci/derive-claim-status.mjs +74 -0
- package/scripts/ci/trust-reconcile.js +957 -103
- package/scripts/git-status.sh +2 -2
- package/scripts/hooks/claude-telemetry-hook.js +37 -3
- package/scripts/hooks/codex-telemetry-hook.js +36 -2
- package/scripts/hooks/config-protection.js +102 -30
- package/scripts/hooks/evidence-capture.js +3 -3
- package/scripts/hooks/lib/actor-identity.js +368 -0
- package/scripts/hooks/lib/config-protection-remedies.js +69 -0
- package/scripts/hooks/lib/liveness-heartbeat.js +361 -0
- package/scripts/hooks/lib/liveness-policy.js +127 -0
- package/scripts/hooks/lib/liveness-read.js +105 -12
- package/scripts/hooks/lib/liveness-write.js +46 -0
- package/scripts/hooks/lib/local-artifact-paths.js +12 -6
- package/scripts/hooks/opencode-telemetry-hook.js +27 -1
- package/scripts/hooks/pi-telemetry-hook.js +27 -1
- package/scripts/hooks/stop-goal-fit.js +157 -26
- package/scripts/hooks/workflow-steering.js +77 -3
- package/scripts/install-codex-home.sh +138 -38
- package/scripts/statusline/flow-agents-statusline.js +2 -2
- package/src/cli/assignment-provider.ts +845 -0
- package/src/cli/console-learning-projection.ts +3 -2
- package/src/cli/effective-assignment-provider-settings.ts +112 -0
- package/src/cli/init.ts +101 -21
- package/src/cli/kit.ts +37 -6
- package/src/cli/public-api.test.mjs +58 -6
- package/src/cli/pull-work-provider.ts +1 -1
- package/src/cli/trust-bundle-policy-order.test.mjs +87 -0
- package/src/cli/usage-feedback.ts +3 -3
- package/src/cli/validate-hook-influence.ts +1 -0
- package/src/cli/validate-workflow-artifacts.ts +27 -7
- package/src/cli/veritas-readiness-adapter.test.mjs +267 -0
- package/src/cli/workflow-artifact-cleanup-audit.ts +35 -2
- package/src/cli/workflow-sidecar.ts +933 -168
- package/src/cli.ts +6 -0
- package/src/flow-kit/validate.ts +74 -1
- package/src/index.ts +6 -2
- package/src/lib/flow-resolver.ts +123 -55
- package/src/lib/local-artifact-root.ts +24 -5
- package/src/lib/workflow-learning-projection.ts +2 -2
- package/src/runtime-adapters.ts +61 -15
- package/src/tools/build-universal-bundles.ts +49 -16
- package/src/tools/generate-context-map.ts +10 -8
- package/src/tools/validate-source-tree.ts +24 -1
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# Assignment Provider Contract
|
|
2
|
+
|
|
3
|
+
This contract defines the provider-neutral vocabulary for durable work-item ownership: who has
|
|
4
|
+
claimed a subject, how that claim is represented, and how it is read back safely. It formalizes
|
|
5
|
+
[ADR 0021: Assignment Leases and Stale-Claim Takeover](../../docs/adr/0021-assignment-leases-and-stale-claim-takeover.md)
|
|
6
|
+
as the third provider leg beside `WorkItemProvider` and `BoardProvider`
|
|
7
|
+
(`context/contracts/work-item-contract.md`) and `ChangeProvider`. GitHub is the first concrete
|
|
8
|
+
mapping for this contract, not the generic vocabulary — Linear, Jira, GitLab, and a local-file
|
|
9
|
+
provider for tracker-less repos and evals all map the same operations.
|
|
10
|
+
|
|
11
|
+
## Terminology: three distinct "claim" concepts
|
|
12
|
+
|
|
13
|
+
This repository uses the word "claim" for three unrelated things. Always qualify in prose; never
|
|
14
|
+
write bare "claim" where the meaning is not obvious from surrounding context:
|
|
15
|
+
|
|
16
|
+
| Term | Layer | Meaning | Where it lives |
|
|
17
|
+
| --- | --- | --- | --- |
|
|
18
|
+
| **assignment claim** | this contract | Durable, provider-recorded ownership of a work item | `AssignmentProvider.claim()`, this doc |
|
|
19
|
+
| **liveness claim** | ADR 0012 | Ephemeral, TTL-reaped presence/heartbeat event | `liveness claim` (`workflow-sidecar.ts`), `freshHolders` (`liveness-read.js`) |
|
|
20
|
+
| **trust claim** | ADR 0010 / ADR 0017 | A Hachure `trust.bundle` evidence claim (kit-typed, verification status) | `workflow-sidecar.ts claim <id> <dir>` (`claimLookup`) |
|
|
21
|
+
|
|
22
|
+
An assignment claim's *effective state* is never computed from the assignment layer alone — it is
|
|
23
|
+
always joined against a liveness claim's freshness (see the join table below).
|
|
24
|
+
|
|
25
|
+
## AssignmentProvider Operations
|
|
26
|
+
|
|
27
|
+
Provider-neutral interface, verbatim from ADR 0021 §2:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
AssignmentProvider:
|
|
31
|
+
claim(subjectId, actor, meta) # assign + attach machine-readable claim record
|
|
32
|
+
release(subjectId, actor, meta) # unassign + handoff note
|
|
33
|
+
supersede(subjectId, from, to, meta) # reassign with audit trail
|
|
34
|
+
status(subjectId) -> {assignee?, actor?, claimedAt?, meta?}
|
|
35
|
+
list(actor?) -> [subjectId]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
| Operation | Arguments | Effect | Returns |
|
|
39
|
+
| --- | --- | --- | --- |
|
|
40
|
+
| `claim` | `subjectId`, `actor`, `meta` | Records durable ownership: assignee (or local-file record), a claim marker, and a versioned claim record carrying the full actor struct. | void (caller re-reads via `status` to confirm) |
|
|
41
|
+
| `release` | `subjectId`, `actor`, `meta` | Clears durable ownership and leaves a handoff note. Normally invoked by the incumbent actor at clean session end. | void |
|
|
42
|
+
| `supersede` | `subjectId`, `from`, `to`, `meta` | Reassigns ownership from a lapsed actor to a successor, with an audit-trail note explaining why (staleness, explicit human confirmation). | void |
|
|
43
|
+
| `status` | `subjectId` | Reads current assignment state without joining liveness. | `{ assignee?, actor?, claimedAt?, meta? }` — the raw assignment-layer read |
|
|
44
|
+
| `list` | `actor?` (optional filter) | Enumerates subject ids currently claimed, optionally filtered to one actor. | `[subjectId]` |
|
|
45
|
+
|
|
46
|
+
`status()` alone is **assignment-layer truth only** — it does not tell a caller whether the claim
|
|
47
|
+
is fresh. Callers that need to decide "is this work available" must compute the join described
|
|
48
|
+
next, not call `status()` in isolation.
|
|
49
|
+
|
|
50
|
+
**Actor identity is runtime-agnostic**: `{ runtime, session_id, host, human? }`. Claude Code,
|
|
51
|
+
codex, opencode, and pi sessions, and humans, are all actors. Reuse the exact struct
|
|
52
|
+
`scripts/hooks/lib/actor-identity.js`'s `resolveActor`/`serializeActor` already define — do not
|
|
53
|
+
fork a second actor concept. `subject_id` reuses `workItemSlug`'s `owner/repo#id` convention
|
|
54
|
+
(the same string the deterministic session slug derives from) rather than inventing a second
|
|
55
|
+
identifier scheme.
|
|
56
|
+
|
|
57
|
+
## The assignment ⋈ liveness join
|
|
58
|
+
|
|
59
|
+
Effective claim state is always a **join** of two layers with distinct jobs. Neither layer is
|
|
60
|
+
trusted alone:
|
|
61
|
+
|
|
62
|
+
| Layer | Records | Lifetime | Medium |
|
|
63
|
+
| --- | --- | --- | --- |
|
|
64
|
+
| **Assignment** | intent / ownership | durable, survives crashes | provider (issue assignee/label/comment, or local-file record) |
|
|
65
|
+
| **Liveness** | presence / freshness | ephemeral, TTL-reaped | ADR 0012 claim stream (`freshHolders`) |
|
|
66
|
+
|
|
67
|
+
Readers compute the join from `{ assignment: AssignmentStatus, freshHolders: FreshHolder[] }` to
|
|
68
|
+
one of five effective states:
|
|
69
|
+
|
|
70
|
+
| Assignment | Liveness | Effective state | `pull-work` treatment |
|
|
71
|
+
| --- | --- | --- | --- |
|
|
72
|
+
| assigned | fresh heartbeat | **held** | excluded |
|
|
73
|
+
| assigned | stale / absent | **reclaimable** | offered, via takeover protocol (ADR 0021 §5, out of this contract's scope) |
|
|
74
|
+
| assigned (human) | n/a (humans don't heartbeat) | **human-held** | surfaced, never auto-taken (see below) |
|
|
75
|
+
| unassigned | fresh (claim only) | **held** (assignment lagging) | excluded |
|
|
76
|
+
| unassigned | absent | **free** | offered |
|
|
77
|
+
|
|
78
|
+
This join rule is what makes lost locks structurally impossible: staleness — not assignment — is
|
|
79
|
+
what excludes, so an orphaned assignee/label/record from a dead session can never gate work.
|
|
80
|
+
|
|
81
|
+
The join is a pure function; reuse `scripts/hooks/lib/liveness-read.js`'s exported
|
|
82
|
+
`freshHolders(events, slug, selfActor, nowMs)` for the liveness half rather than re-implementing
|
|
83
|
+
TTL/staleness arithmetic. The join table itself (assignment status × liveness freshness →
|
|
84
|
+
effective state) is the only new logic — it has no other implementation in this repository.
|
|
85
|
+
|
|
86
|
+
## Lazy-correction transition table
|
|
87
|
+
|
|
88
|
+
Nothing updates the provider on a timer; every mutation has a responsible actor, invoked at a
|
|
89
|
+
specific lifecycle moment (ADR 0021 §4). This table names every transition for completeness; it
|
|
90
|
+
also records which issue implements each row so a future reader does not assume any single issue
|
|
91
|
+
delivers all four:
|
|
92
|
+
|
|
93
|
+
| Transition | Mutator | When | Owning issue |
|
|
94
|
+
| --- | --- | --- | --- |
|
|
95
|
+
| `claim` | the claiming session | at selection | **#290 (this issue)** |
|
|
96
|
+
| `clean_release` | the incumbent (Stop hook / terminal `advance-state`) | session end — unassign + handoff comment | #292 |
|
|
97
|
+
| `supersede` | the successor, inside the takeover protocol | after the grace beat | #294 |
|
|
98
|
+
| `crash_no_successor` | nobody, initially; corrected by the next actor to want the subject, or the janitor | lazily, or on a janitor sweep | out of scope — the Console relay's first cross-machine duty (ADR 0021 §4/§7) |
|
|
99
|
+
|
|
100
|
+
Lazy correction is *safe* by the join rule above (stale assignment excludes nothing), but leaves
|
|
101
|
+
the human-visible board stale in the crash case until the next claim attempt or a janitor sweep
|
|
102
|
+
corrects it.
|
|
103
|
+
|
|
104
|
+
## Human-assignee ask-first policy
|
|
105
|
+
|
|
106
|
+
Humans do not heartbeat, so `assigned-to-human + no-liveness` is **normal, not stale** — it must
|
|
107
|
+
never be treated as `reclaimable`. Agents surface idle human assignments ("assigned to `brian` 3
|
|
108
|
+
days ago, no linked activity — reclaim?") and act only on explicit confirmation.
|
|
109
|
+
|
|
110
|
+
- Default behavior: `ask_first`.
|
|
111
|
+
- The threshold (`idle_threshold_days`, default `3`, matching ADR 0021 §6's own illustrative
|
|
112
|
+
example) and behavior (`ask_first` | `never_reclaim`) are a policy knob in
|
|
113
|
+
`assignment-provider-settings.schema.json` (`policy.human_assignee_policy`), not a hardcoded
|
|
114
|
+
constant.
|
|
115
|
+
- **Non-goal:** never auto-supersede a human. The join function must gate on the actor struct's
|
|
116
|
+
`human` field being present (not absent/null) — never on a heuristic over the GitHub login name
|
|
117
|
+
— so a human assignee is always classified `human-held`, regardless of idle duration, and is
|
|
118
|
+
never silently reclaimed by any automated path.
|
|
119
|
+
- This contract and its settings schema define the policy knob and the read-side data a caller
|
|
120
|
+
needs to surface the question (assignee identity, idle duration). The actual "ask the user"
|
|
121
|
+
interaction belongs to whichever skill consumes the join result (`pull-work`), which records it
|
|
122
|
+
as an alignment question rather than a new UI surface.
|
|
123
|
+
|
|
124
|
+
## Versioned claim-record format
|
|
125
|
+
|
|
126
|
+
The durable claim record is a single JSON object, versioned via `schema_version` so a reader can
|
|
127
|
+
detect an incompatible future shape before parsing fields it does not understand:
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"schema_version": "1.0",
|
|
132
|
+
"role": "AssignmentClaimRecord",
|
|
133
|
+
"subject_id": "kontourai/flow-agents#290",
|
|
134
|
+
"actor": { "runtime": "claude-code", "session_id": "...", "host": "...", "human": null },
|
|
135
|
+
"claimed_at": "2026-07-02T00:00:00Z",
|
|
136
|
+
"ttl_seconds": 1800,
|
|
137
|
+
"branch": "agent/<actor>/<slug>",
|
|
138
|
+
"artifact_dir": ".kontourai/flow-agents/<slug>",
|
|
139
|
+
"status": "claimed"
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
| Field | Required | Description |
|
|
144
|
+
| --- | --- | --- |
|
|
145
|
+
| `schema_version` | yes | Version of this record shape, `"1.0"`. |
|
|
146
|
+
| `role` | yes | Constant `"AssignmentClaimRecord"`, for readers scanning mixed content (e.g. a GitHub comment thread) for this record type. |
|
|
147
|
+
| `subject_id` | yes | The claimed work item, in `owner/repo#id` form — the same string `workItemSlug` derives the deterministic session slug from. |
|
|
148
|
+
| `actor` | yes | `{ runtime, session_id, host, human? }` — the exact struct `actor-identity.js` defines. `human` is set (non-null) only for a human assignee; its presence, not a username heuristic, gates the human-held join state. |
|
|
149
|
+
| `claimed_at` | yes | ISO-8601 timestamp the claim was recorded. Mirrors the liveness stream's own claim-event field so a reader compares freshness with one mental model across both layers, even though the two are stored in different media. |
|
|
150
|
+
| `ttl_seconds` | yes | Same field name/semantics as the liveness stream's `ttlSeconds` (default `1800`). |
|
|
151
|
+
| `branch` | yes | The branch this actor is working on, per the `agent/<actor>/<slug>` convention. |
|
|
152
|
+
| `artifact_dir` | yes | The deterministic workflow artifact directory for this subject, so a successor inherits the same session. |
|
|
153
|
+
| `status` | yes | `"claimed"` today; future transitions may add `"released"` / `"superseded"` values as the corresponding mutator (see the transition table) is implemented. |
|
|
154
|
+
|
|
155
|
+
**Versioning rule:** bump `schema_version` only on an incompatible change (matching
|
|
156
|
+
`artifact-contract.md`'s existing sidecar rule: "Keep `schema_version` at `1.0` until the schema
|
|
157
|
+
changes incompatibly"). Additive, optional fields do not require a bump.
|
|
158
|
+
|
|
159
|
+
### GitHub mapping
|
|
160
|
+
|
|
161
|
+
The GitHub implementation represents the record as:
|
|
162
|
+
|
|
163
|
+
- **assignee**: the notification/board hook.
|
|
164
|
+
- **a single `agent:claimed` label** (default name, configurable via
|
|
165
|
+
`policy.label_name`): the board filter.
|
|
166
|
+
- **a machine-readable claim comment**: human-readable prose above a fenced JSON block containing
|
|
167
|
+
the record above, located via a fixed marker (default
|
|
168
|
+
`<!-- flow-agents:assignment-claim -->`, configurable via `policy.claim_comment_marker`) so the
|
|
169
|
+
board stays legible to a human without tooling, while remaining machine-parseable.
|
|
170
|
+
|
|
171
|
+
The comment carries identity because the assignee field cannot: N agent sessions typically share
|
|
172
|
+
one GitHub account, so per-session identity lives in the attached record. Each provider decides
|
|
173
|
+
what it can natively represent versus what goes in the record.
|
|
174
|
+
|
|
175
|
+
### local-file mapping
|
|
176
|
+
|
|
177
|
+
For tracker-less repos and evals, the same record is written to a JSON file under the artifact
|
|
178
|
+
root (`<artifact-root>/assignment/<sanitized-subject-id>.json`), full read-modify-write, no
|
|
179
|
+
external process involved. This path is the one that does real I/O inside the CLI, since there is
|
|
180
|
+
no external mutation to defer to a skill.
|
|
181
|
+
|
|
182
|
+
**`--actor-json` asymmetry (fix-plan iteration 1, F5, intentional):** local-file `claim`/`release`
|
|
183
|
+
falls back to auto-resolving the actor from the live environment (`resolveActor(process.env)`) when
|
|
184
|
+
`--actor-json` is omitted; `render-claim`/`render-supersede` (GitHub) always require `--actor-json`
|
|
185
|
+
explicitly and fail loud without it. This is intentional, not a footgun to fix later — the
|
|
186
|
+
currently-wired `pull-work` skill always passes `--actor-json` for both provider kinds, so the
|
|
187
|
+
asymmetry has no effect on the shipped path today, but a future direct-CLI caller relying on
|
|
188
|
+
local-file `claim` to fail the same way `render-claim` does when the actor can't be determined
|
|
189
|
+
should pass `--actor-json` explicitly rather than relying on the auto-resolve fallback.
|
|
190
|
+
|
|
191
|
+
## Implementation Note
|
|
192
|
+
|
|
193
|
+
`schemas/assignment-provider-settings.schema.json` is the settings schema companion to this
|
|
194
|
+
contract — it configures `provider.kind` (`github` | `local-file`), the label name, the claim
|
|
195
|
+
comment marker, and the human-assignee policy knob described above.
|
|
196
|
+
|
|
197
|
+
The GitHub write path follows this repository's `publish-change-helper.ts` precedent — **render,
|
|
198
|
+
don't execute**: the CLI emits the exact, deterministic `gh` argv and comment body for a mutation
|
|
199
|
+
as a pure function; the calling skill runs that exact argv via its Bash tool (never freehand `gh`
|
|
200
|
+
text), then re-fetches and feeds the result back into the CLI's `status` parser to close the round
|
|
201
|
+
trip. This is a deliberate divergence from a literal "CLI shells out to `gh` itself" design: it
|
|
202
|
+
matches the one existing same-shaped precedent in this repository, keeps operational concerns
|
|
203
|
+
(auth, rate limiting, retries, partial-failure sequencing across separate `gh` calls) at the skill
|
|
204
|
+
layer where Bash-tool error handling already lives, and avoids introducing this repository's first
|
|
205
|
+
`execFileSync`-to-`gh` code path inside compiled code without a dedicated decision. A future
|
|
206
|
+
implementer of the GitHub mutation path should read this note, not re-derive the reasoning from
|
|
207
|
+
scratch — see the `#290` plan artifact's Design Decision 1 for the full evidence trail if more
|
|
208
|
+
detail is needed.
|
|
209
|
+
|
|
210
|
+
**`gh_commands` execution contract (fix-plan iteration 1, F4):** every `render-*` subcommand's
|
|
211
|
+
`gh_commands` field is a JSON array of **argv arrays** (one element per `gh` argument), not a
|
|
212
|
+
shell-command string. The calling skill MUST execute each entry as argv — every element passed as
|
|
213
|
+
its own separate Bash-tool argument — and MUST NOT concatenate the elements into a single shell
|
|
214
|
+
string or run them via `bash -c`/shell re-interpretation. This matters specifically because
|
|
215
|
+
`claim_comment_body` (and, for `render-supersede`, `previous_record`) can carry attacker-influenced
|
|
216
|
+
text: any GitHub user who can comment on the issue can post a forged claim-marker comment (see the
|
|
217
|
+
sanitization note below), and reconstructing a shell string from that content would reintroduce a
|
|
218
|
+
shell-injection surface the render/execute split is designed to avoid. This is stated explicitly in
|
|
219
|
+
`kits/builder/skills/pull-work/SKILL.md`'s "Assignment Claim On Selection" section as well — this
|
|
220
|
+
paragraph is the contract-side mirror of that instruction, not a duplicate source of truth to drift
|
|
221
|
+
from it.
|
|
222
|
+
|
|
223
|
+
**Untrusted claim-record fields (fix-plan iteration 1, F2):** `extractClaimRecord()` parses the
|
|
224
|
+
fenced JSON claim record out of *any* issue comment matching the claim marker — posting a comment
|
|
225
|
+
requires no elevated access, unlike the assignee/label mutations this contract otherwise gates. Its
|
|
226
|
+
returned record's string fields (`subject_id`, `branch`, `artifact_dir`, `actor.*`, including
|
|
227
|
+
`actor.human`, and each `audit_trail` entry's actor/`reason`) are therefore treated as untrusted
|
|
228
|
+
display input and are run through a control-character-strip + length-cap sanitizer (mirroring
|
|
229
|
+
`workflow-sidecar.ts`'s `stripControlCharsForDisplay`, the established #287/#320 mitigation for
|
|
230
|
+
this input class) before they leave the module in `status`/`list` output. This is display-only — it
|
|
231
|
+
never changes the assignment ⋈ liveness join's classification logic, only the surfaced string
|
|
232
|
+
content.
|
|
233
|
+
|
|
234
|
+
No part of this system writes to the provider on a timer or heartbeats to it (ADR 0021 §4/§7).
|
|
235
|
+
Every write is triggered by a specific lifecycle moment named in the transition table above. The
|
|
236
|
+
one optional exception is a comment-body refresh at an explicit phase transition
|
|
237
|
+
(`policy.comment_refresh_on_phase_transition`, default `false`) — cheap because it reuses the same
|
|
238
|
+
render path already built for `claim`, just called again with an updated `status`/`claimed_at`
|
|
239
|
+
field.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Builder Kit Workflow State Contract
|
|
2
2
|
|
|
3
|
+
> Read [`context/contracts/standing-directives.md`](standing-directives.md) — ratified owner directives that override default engineering conservatism.
|
|
4
|
+
|
|
3
5
|
This contract defines the durable routing state for Builder Kit build-flow pickup and resume. It keeps `state.json` limited to canonical Flow Agents workflow routing and stores rich pickup decisions in a documented Probe record sidecar referenced by `state.json`, `handoff.json`, and the session artifact.
|
|
4
6
|
|
|
5
7
|
Builder Kit owns product-level build-flow coordination. Flow Agents owns the workflow harness, artifact conventions, primitive execution, and evidence gates. Flow remains the owner of Flow gate semantics. Builder Kit contracts may route to Flow Agents primitives, but must not redefine pass, fail, approval, or release authority semantics.
|
|
@@ -25,6 +27,7 @@ Every Builder Kit build-flow pause, resume, or step transition must make the fol
|
|
|
25
27
|
| Field | Durable location | Required meaning |
|
|
26
28
|
| --- | --- | --- |
|
|
27
29
|
| current step | `state.phase`, `state.status`, and Probe record `current_step` | The current Builder Kit step or direct Flow Agents primitive. |
|
|
30
|
+
| branch | `state.json.branch`; seeded in the session Markdown's `branch:` line | The `agent/<actor>/<slug>` routing branch `ensure-session` derives for a new session (optional field for migration honesty — see `schemas/workflow-state.schema.json`); an explicit `--branch` overrides; an existing session's already-recorded branch is never re-derived (see [ADR 0021](../../docs/adr/0021-assignment-leases-and-stale-claim-takeover.md) §3 and §5). |
|
|
28
31
|
| next step | `state.next_action` and Probe record `next_step` | The next step to run after resume or after the current primitive exits. |
|
|
29
32
|
| route reason | Probe record `route_reason`; summarized in `state.next_action.summary` | Why this route was selected, including missing state, evidence, decisions, or blockers. |
|
|
30
33
|
| selected work item refs | Probe record `selected_work_items`; optionally linked in `handoff.json` | Neutral work item references from the work-item contract. |
|
|
@@ -44,7 +47,7 @@ Every Builder Kit build-flow pause, resume, or step transition must make the fol
|
|
|
44
47
|
|
|
45
48
|
## Probe Record
|
|
46
49
|
|
|
47
|
-
A Builder Kit Probe record is a JSON sidecar beside the other workflow artifacts, for example `.flow-agents/<slug>/builder-kit-probe.json`. It is the durable location for pickup/design context that would otherwise make `state.json` too broad.
|
|
50
|
+
A Builder Kit Probe record is a JSON sidecar beside the other workflow artifacts, for example `.kontourai/flow-agents/<slug>/builder-kit-probe.json`. It is the durable location for pickup/design context that would otherwise make `state.json` too broad.
|
|
48
51
|
|
|
49
52
|
Required shape:
|
|
50
53
|
|
|
@@ -168,7 +171,7 @@ Baseline freshness example for missing historical `planned_base_sha`:
|
|
|
168
171
|
{
|
|
169
172
|
"id": "source_artifact",
|
|
170
173
|
"description": "Source shaped artifact or pickup artifact used to accept the fallback baseline.",
|
|
171
|
-
"source": ".flow-agents/<slug>/<slug>--idea-to-backlog.md",
|
|
174
|
+
"source": ".kontourai/flow-agents/<slug>/<slug>--idea-to-backlog.md",
|
|
172
175
|
"example_value": ".flow-agents/builder-kit-not-verified-resolution-hints/builder-kit-not-verified-resolution-hints--idea-to-backlog.md"
|
|
173
176
|
}
|
|
174
177
|
],
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# Decision Registry Contract
|
|
2
|
+
|
|
3
|
+
> Read [`context/contracts/standing-directives.md`](standing-directives.md) — ratified owner directives that override default engineering conservatism.
|
|
4
|
+
|
|
5
|
+
Normative contract for the topic-keyed decision registry. This is the source of
|
|
6
|
+
truth for how NEW decisions are recorded in a Kontour repository. Numbered ADRs
|
|
7
|
+
under `docs/adr/` are frozen history and are never written for new decisions
|
|
8
|
+
(see [Relationship to ADRs](#relationship-to-adrs-and-grill-with-docs)).
|
|
9
|
+
|
|
10
|
+
Machine-checkable structure lives in `schemas/decision-record.schema.json`; the
|
|
11
|
+
validator/generator is `scripts/check-decisions.cjs`, exposed as
|
|
12
|
+
`npm run check:decisions` and `npm run gen:decisions-index` and wired into the
|
|
13
|
+
required `source-and-static` CI lane.
|
|
14
|
+
|
|
15
|
+
## Why topic-keyed living records
|
|
16
|
+
|
|
17
|
+
Numbered ADRs accumulate three failure modes at multi-contributor, multi-repo
|
|
18
|
+
scale: contradictions (a new ADR appends a conflicting decision instead of
|
|
19
|
+
replacing the old one), bloat (derivation context is inlined alongside the
|
|
20
|
+
decision), and numbering collisions (two contributors both grab `0021-`). The
|
|
21
|
+
registry removes all three by construction:
|
|
22
|
+
|
|
23
|
+
- **One file per decision subject**, keyed by a vocabulary noun, not a number.
|
|
24
|
+
- **Supersession is an edit**, so the current answer is always the only answer.
|
|
25
|
+
- **Derivation context is linked, not inlined**, so files stay lean.
|
|
26
|
+
|
|
27
|
+
## File location and shape
|
|
28
|
+
|
|
29
|
+
- Each decision lives at `docs/decisions/<topic-slug>.md`.
|
|
30
|
+
- Exactly **one file per decision SUBJECT**. If two questions have the same
|
|
31
|
+
subject, they share a file; if a file is answering two subjects, split it.
|
|
32
|
+
- A generated index lives at `docs/decisions/index.md` (see [Index](#index)).
|
|
33
|
+
- The file holds ONLY the current decision plus lean rationale. It does not
|
|
34
|
+
inline transcripts, exploration, meeting notes, or superseded prose.
|
|
35
|
+
|
|
36
|
+
A topic file is YAML frontmatter followed by a short Markdown body:
|
|
37
|
+
|
|
38
|
+
```markdown
|
|
39
|
+
---
|
|
40
|
+
status: current
|
|
41
|
+
subject: Decision records
|
|
42
|
+
decided: 2026-07-03
|
|
43
|
+
evidence:
|
|
44
|
+
- kind: issue
|
|
45
|
+
ref: https://github.com/kontourai/flow-agents/issues/310
|
|
46
|
+
- kind: session-archive
|
|
47
|
+
ref: .kontourai/flow-agents/decision-registry-shape/decision-registry-shape--idea-to-backlog.md
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
# Decision records
|
|
51
|
+
|
|
52
|
+
The current answer, plus lean rationale. Derivation context is linked via
|
|
53
|
+
`evidence[]`, never pasted here.
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Slug rules: vocabulary is the namespace
|
|
57
|
+
|
|
58
|
+
- Slugs are **nouns from the repository's CONTEXT.md domain vocabulary**. The
|
|
59
|
+
ubiquitous language is the topic namespace; topic identity is downstream of it.
|
|
60
|
+
- Slugs are lowercase kebab-case: `^[a-z0-9]+(-[a-z0-9]+)*$`, matching a
|
|
61
|
+
glossary term (e.g. the glossary term "Decision Records" ->
|
|
62
|
+
`decision-records.md`).
|
|
63
|
+
- **If the subject term is absent from CONTEXT.md, add it to CONTEXT.md first**,
|
|
64
|
+
then create the topic file. This keeps slugs stable and collision-free: two
|
|
65
|
+
contributors deciding the same subject land on the same slug rather than
|
|
66
|
+
competing for the next number.
|
|
67
|
+
|
|
68
|
+
## Frontmatter fields
|
|
69
|
+
|
|
70
|
+
Validated by `schemas/decision-record.schema.json`:
|
|
71
|
+
|
|
72
|
+
| Field | Required | Meaning |
|
|
73
|
+
| --- | --- | --- |
|
|
74
|
+
| `status` | yes | `current` \| `superseded` \| `merged` \| `needs-decision` (see [Status](#status-values)). |
|
|
75
|
+
| `subject` | yes | The decision subject, a CONTEXT.md vocabulary noun phrase. |
|
|
76
|
+
| `decided` | yes | ISO date `YYYY-MM-DD` the current decision was ratified. |
|
|
77
|
+
| `evidence[]` | yes | `{kind, ref}` links to durable provenance. Never a secret. |
|
|
78
|
+
| `supersedes[]` | no | Topic slugs whose subjects this file absorbed. |
|
|
79
|
+
| `superseded_by` | when superseded | The slug that now carries the answer. |
|
|
80
|
+
| `merged_into` | when merged | The slug this subject was folded into. |
|
|
81
|
+
|
|
82
|
+
### Status values
|
|
83
|
+
|
|
84
|
+
- **`current`** — this file holds the live answer for its subject. Must not
|
|
85
|
+
carry `superseded_by` or `merged_into`.
|
|
86
|
+
- **`superseded`** — a tombstone: the subject moved to a different topic slug
|
|
87
|
+
(renamed or split). Requires `superseded_by`.
|
|
88
|
+
- **`merged`** — a tombstone: the subject was folded into another topic. Requires
|
|
89
|
+
`merged_into`.
|
|
90
|
+
- **`needs-decision`** — a stub that names an open subject with no ratified answer
|
|
91
|
+
yet. It carries provenance `evidence[]` (e.g. the frozen ADR whose subject is
|
|
92
|
+
still open) but no live decision body. This value exists so ADR freeze tooling
|
|
93
|
+
(issue #314) can record that a frozen ADR's subject still needs a living
|
|
94
|
+
decision without inventing an answer. A `needs-decision` stub is not a
|
|
95
|
+
tombstone and must not carry `superseded_by`/`merged_into`.
|
|
96
|
+
|
|
97
|
+
### Evidence refs
|
|
98
|
+
|
|
99
|
+
Derivation context is LINKED, never inlined. Each `evidence[]` entry is
|
|
100
|
+
`{kind, ref}` where `kind` is one of `issue`, `pr`, `commit`, `session-archive`,
|
|
101
|
+
`adr`, `doc`, `url`:
|
|
102
|
+
|
|
103
|
+
- **`session-archive`** — a path to an archived session artifact (under
|
|
104
|
+
`.kontourai/`) promoted at retirement. Grilling/probe transcripts retire into
|
|
105
|
+
the session archive and are linked here as decision provenance.
|
|
106
|
+
- **`adr`** — a frozen numbered ADR under `docs/adr/` that is provenance for this
|
|
107
|
+
decision.
|
|
108
|
+
- **`issue`/`pr`/`commit`** — GitHub references (number, URL, or SHA).
|
|
109
|
+
- **`doc`/`url`** — a repository document path or external permalink.
|
|
110
|
+
|
|
111
|
+
`ref` values must never contain secret-shaped material (AWS access keys, GitHub
|
|
112
|
+
tokens, private-key blocks, JWTs, or `secret:`/`token:`-style literals). The
|
|
113
|
+
validator refuses them; link durable provenance, never a credential.
|
|
114
|
+
|
|
115
|
+
## Supersession by edit
|
|
116
|
+
|
|
117
|
+
The normal way a decision changes is: **edit the topic file in place.** Update
|
|
118
|
+
the body to the new decision, bump `decided`, and add an `evidence[]` ref to the
|
|
119
|
+
PR/issue that changed it. There is no second file, no appendix, and no
|
|
120
|
+
contradiction — the file always states exactly one current answer.
|
|
121
|
+
|
|
122
|
+
Example — the pre-edit file:
|
|
123
|
+
|
|
124
|
+
```markdown
|
|
125
|
+
---
|
|
126
|
+
status: current
|
|
127
|
+
subject: Artifact retention window
|
|
128
|
+
decided: 2026-04-01
|
|
129
|
+
evidence:
|
|
130
|
+
- kind: pr
|
|
131
|
+
ref: https://github.com/kontourai/flow-agents/pull/120
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
# Artifact retention window
|
|
135
|
+
|
|
136
|
+
Runtime artifacts are retained for 30 days, then archived.
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
After a later decision to shorten the window, the SAME file becomes:
|
|
140
|
+
|
|
141
|
+
```markdown
|
|
142
|
+
---
|
|
143
|
+
status: current
|
|
144
|
+
subject: Artifact retention window
|
|
145
|
+
decided: 2026-07-01
|
|
146
|
+
evidence:
|
|
147
|
+
- kind: pr
|
|
148
|
+
ref: https://github.com/kontourai/flow-agents/pull/120
|
|
149
|
+
- kind: pr
|
|
150
|
+
ref: https://github.com/kontourai/flow-agents/pull/305
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
# Artifact retention window
|
|
154
|
+
|
|
155
|
+
Runtime artifacts are retained for 14 days, then archived.
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The old answer is gone from the head; its provenance survives in the linked PRs.
|
|
159
|
+
|
|
160
|
+
## Tombstones: when a topic moves or merges
|
|
161
|
+
|
|
162
|
+
Editing covers a decision changing. The rarer case is a SUBJECT moving to a
|
|
163
|
+
different slug. Then the old file becomes a tombstone so inbound links and
|
|
164
|
+
retrieval still resolve.
|
|
165
|
+
|
|
166
|
+
### `superseded_by` — the subject moved to another slug
|
|
167
|
+
|
|
168
|
+
Use when a subject is renamed or split and its answer now lives under a different
|
|
169
|
+
slug. The old file:
|
|
170
|
+
|
|
171
|
+
```markdown
|
|
172
|
+
---
|
|
173
|
+
status: superseded
|
|
174
|
+
subject: Artifact retention window
|
|
175
|
+
decided: 2026-07-02
|
|
176
|
+
superseded_by: artifact-lifecycle
|
|
177
|
+
evidence:
|
|
178
|
+
- kind: pr
|
|
179
|
+
ref: https://github.com/kontourai/flow-agents/pull/330
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
# Artifact retention window
|
|
183
|
+
|
|
184
|
+
Superseded. The current decision for this subject lives in
|
|
185
|
+
[artifact-lifecycle](./artifact-lifecycle.md).
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### `merged_into` — the subject folded into an existing topic
|
|
189
|
+
|
|
190
|
+
Use when a subject is absorbed by another existing topic. The absorbed file:
|
|
191
|
+
|
|
192
|
+
```markdown
|
|
193
|
+
---
|
|
194
|
+
status: merged
|
|
195
|
+
subject: Artifact retention window
|
|
196
|
+
decided: 2026-07-02
|
|
197
|
+
merged_into: artifact-lifecycle
|
|
198
|
+
evidence:
|
|
199
|
+
- kind: pr
|
|
200
|
+
ref: https://github.com/kontourai/flow-agents/pull/330
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
# Artifact retention window
|
|
204
|
+
|
|
205
|
+
Merged into [artifact-lifecycle](./artifact-lifecycle.md).
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
The surviving file may record what it absorbed with `supersedes: [artifact-retention-window]`.
|
|
209
|
+
|
|
210
|
+
Both tombstone forms require the target slug to exist (a validator error
|
|
211
|
+
otherwise) and must not point at their own slug.
|
|
212
|
+
|
|
213
|
+
## Retrieval-at-write
|
|
214
|
+
|
|
215
|
+
Before recording a decision, **consult `docs/decisions/index.md`** (the
|
|
216
|
+
always-loaded slug + one-liner index) and decide **revise-vs-create**:
|
|
217
|
+
|
|
218
|
+
1. If an existing topic covers the subject, **revise that file** (edit in place,
|
|
219
|
+
or tombstone + move if the subject itself is changing identity).
|
|
220
|
+
2. If no topic covers it, confirm the subject noun exists in CONTEXT.md (add it
|
|
221
|
+
if absent), then **create** `docs/decisions/<slug>.md`.
|
|
222
|
+
|
|
223
|
+
This retrieval-at-write step, plus a health check at rest (the validator + index
|
|
224
|
+
freshness in CI), is sufficient at this cardinality; no embeddings or semantic
|
|
225
|
+
topic matching are required.
|
|
226
|
+
|
|
227
|
+
## Index
|
|
228
|
+
|
|
229
|
+
`docs/decisions/index.md` is generated by `npm run gen:decisions-index`
|
|
230
|
+
(`scripts/check-decisions.cjs gen-index`). It is deterministic and idempotent: a
|
|
231
|
+
second run with no topic change is diff-clean. It lists each topic slug, its
|
|
232
|
+
status, and a one-line summary (the `subject`, falling back to the first body
|
|
233
|
+
line). Do not edit it by hand. `npm run check:decisions` fails if the index is
|
|
234
|
+
missing or stale, so CI catches an out-of-date index.
|
|
235
|
+
|
|
236
|
+
The index is referenced from `CONTEXT.md` so retrieval-at-write always has a
|
|
237
|
+
cheap, loaded pointer into the registry.
|
|
238
|
+
|
|
239
|
+
## Validation
|
|
240
|
+
|
|
241
|
+
`npm run check:decisions` (wired into the required `source-and-static` CI lane)
|
|
242
|
+
exits nonzero on any of:
|
|
243
|
+
|
|
244
|
+
- invalid frontmatter (missing `status`/`subject`/`decided`/`evidence`);
|
|
245
|
+
- unknown `status`;
|
|
246
|
+
- a secret-shaped `evidence[].ref`;
|
|
247
|
+
- a `superseded_by`/`merged_into`/`supersedes` slug that points at a missing
|
|
248
|
+
topic file;
|
|
249
|
+
- a status/relationship mismatch (e.g. `current` carrying a tombstone field, or
|
|
250
|
+
`superseded` without `superseded_by`);
|
|
251
|
+
- a stale or missing `docs/decisions/index.md`.
|
|
252
|
+
|
|
253
|
+
## Relationship to ADRs and grill-with-docs
|
|
254
|
+
|
|
255
|
+
- **CONTEXT.md is the only external compatibility surface.** Grill-with-docs
|
|
256
|
+
interop reads the domain vocabulary from CONTEXT.md; the registry keys its
|
|
257
|
+
slugs off that same vocabulary. We inherit the grill-with-docs behavior, not
|
|
258
|
+
the numbered-ADR file format.
|
|
259
|
+
- **Numbered ADRs (`docs/adr/NNNN-*.md`) are frozen history.** They are never
|
|
260
|
+
written for new decisions and are never converted into topic files. Existing
|
|
261
|
+
ADRs are frozen-and-indexed by separate tooling (issue #314); a topic file may
|
|
262
|
+
cite a frozen ADR via an `adr` evidence ref as provenance.
|
|
263
|
+
|
|
264
|
+
The pilot record self-hosting this contract is
|
|
265
|
+
[docs/decisions/decision-records.md](../../docs/decisions/decision-records.md).
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Delivery Contract
|
|
2
2
|
|
|
3
|
+
> Read [`context/contracts/standing-directives.md`](standing-directives.md) — ratified owner directives that override default engineering conservatism.
|
|
4
|
+
|
|
3
5
|
Delivery chains planning, execution, review, verification, Goal Fit, and final acceptance until the user-facing goal is genuinely handled.
|
|
4
6
|
|
|
5
7
|
## Workflow
|
|
@@ -59,7 +61,7 @@ After CI passes and the work is merged, released, or otherwise accepted:
|
|
|
59
61
|
- [ ] working artifacts archived or linked
|
|
60
62
|
- [ ] long-lived docs updated with why and how the feature was built
|
|
61
63
|
- [ ] durable docs link back to the provider record, archived plan, or session artifact when useful
|
|
62
|
-
- [ ] local `.flow-agents/` runtime artifacts remain untracked, and durable outcomes are promoted before merge to `main`
|
|
64
|
+
- [ ] local `.kontourai/flow-agents/` runtime artifacts remain untracked, and durable outcomes are promoted before merge to `main`
|
|
63
65
|
- [ ] follow-up issues or learning-review items created for deferred work
|
|
64
66
|
- [ ] **workspace cleaned up after a confirmed merge**: the merge is verified from the provider's own merge record (a merge commit / `mergedAt`), not a green check or a command exit code; then the isolated worktree is removed and the now-merged branch is deleted locally and on the remote, honoring the `worktree_lifecycle` (`retain_until: pr_merged`) recorded at selection. Never delete a branch or worktree before the merge is confirmed. A delivery is not complete while it leaves a stale worktree or merged branch behind.
|
|
65
67
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Execution Contract
|
|
2
2
|
|
|
3
|
+
> Read [`context/contracts/standing-directives.md`](standing-directives.md) — ratified owner directives that override default engineering conservatism.
|
|
4
|
+
|
|
3
5
|
Execution turns an approved plan artifact into code and local evidence while preserving parallel safety.
|
|
4
6
|
|
|
5
7
|
## Required Inputs
|
|
@@ -42,6 +44,29 @@ Execution may upgrade to a stronger mode when risk increases. Downgrades require
|
|
|
42
44
|
- Worker delegation must name the exact worker role (`tool-worker`) rather than spawning an unnamed/default implementation agent.
|
|
43
45
|
- After each wave, collect results, check conflicts, and update the session artifact before starting the next wave.
|
|
44
46
|
|
|
47
|
+
## Delegation: Model Routing
|
|
48
|
+
|
|
49
|
+
Model-routing policy is data, not code: `.datum/config.json` (schema:
|
|
50
|
+
`@kontourai/datum`, provider/role registry) is the source of truth for which
|
|
51
|
+
model backs which delegate role. This contract only says where to read it.
|
|
52
|
+
|
|
53
|
+
- When spawning a delegate, resolve its role via `npx @kontourai/datum resolve <role> --json`
|
|
54
|
+
(or the `@kontourai/datum` library's `resolve()`) and pass the resolved
|
|
55
|
+
`model` explicitly to the delegate invocation. Do not hardcode a model name
|
|
56
|
+
in a skill, agent definition, or generated file — the role name is the
|
|
57
|
+
stable reference; the model it resolves to can change without touching
|
|
58
|
+
delegation call sites.
|
|
59
|
+
- Role selection follows task shape, not delegate identity: fully-specified
|
|
60
|
+
mechanical tasks resolve `delegate-mechanical`; precisely-planned
|
|
61
|
+
implementation tasks resolve `delegate-implementation`; tasks needing design
|
|
62
|
+
latitude resolve `delegate-design`. The orchestrator's own model (planning,
|
|
63
|
+
gates, adversarial verification) resolves `orchestrator`, typically inherited
|
|
64
|
+
rather than overridden.
|
|
65
|
+
- When `datum` (the CLI/library) or `.datum/config.json` is absent or a role
|
|
66
|
+
fails to resolve, fall back to the runtime's inherited model and note the
|
|
67
|
+
fallback in the session/task artifact — do not block delegation on datum
|
|
68
|
+
being present.
|
|
69
|
+
|
|
45
70
|
## Completion Rules
|
|
46
71
|
|
|
47
72
|
Execution is complete only when:
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Governance Adapter Contract
|
|
2
2
|
|
|
3
|
+
> Read [`context/contracts/standing-directives.md`](standing-directives.md) — ratified owner directives that override default engineering conservatism.
|
|
4
|
+
|
|
3
5
|
Governance adapters let Flow Agents ask an external tool for policy, proof, or trust evidence without baking repo-specific policy into Flow Agents core.
|
|
4
6
|
|
|
5
7
|
## Boundary
|