PROPOSAL-LIFECYCLE.md markdown
141 lines 9.2 KB
Raw
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor ⚠ breaking 1 day ago

Proposal lifecycle (Hub)

This document defines states, roles, and identifiers for Knowtation Hub proposals. It is the reference for extending ProposalRecord (Node, canister, OpenAPI) without drift.

States

Status Meaning
proposed Waiting for review; not applied to the canonical vault.
approved Applied to the vault; proposal record kept for audit/history.
discarded Rejected; not applied. May be bulk-discarded when notes are deleted (see HUB-METADATA-BULK-OPS.md).

Allowed transitions:

  • proposedapproved (admin: Approve; may require human evaluation first — see Evaluation below)
  • proposeddiscarded (admin: Discard, or bulk housekeeping)

There is no draft status in the store today; agents create proposed rows via POST /api/v1/proposals.

Roles (Phase 13 + evaluator)

Role List / view proposals Create proposal Submit evaluation Approve / discard
viewer Yes No No No
editor Yes Yes No No
evaluator Yes No Yes Only if HUB_EVALUATOR_MAY_APPROVE=1 (approve only; discard stays admin on Node Hub)
admin Yes Yes Yes Yes

Optional Tier-2 enrichment (POST /api/v1/proposals/:id/enrich when KNOWTATION_HUB_PROPOSAL_ENRICH=1): editor or admin.

Optimistic concurrency: base_state_id

When a proposal targets an existing note path, the client may send base_state_id: a fingerprint of the vault note as the client last saw it (e.g. from GET /api/v1/notes/:path). On Approve, the Hub (self-hosted Node) recomputes the current fingerprint for that path and returns 409 CONFLICT if it does not match either the request body’s base_state_id (if provided) or the value stored on the proposal.

Format kn1_ (FNV-1a 64-bit)

  • Prefix: kn1_
  • Suffix: 16 lowercase hex characters = FNV-1a 64-bit over UTF-8 bytes of canonicalJSON(frontmatterObject) + "\0" + body
  • canonicalJSON means sorted object keys at all levels (see lib/note-state-id.mjs stableStringify).

Absent path (new note; no file at that path yet): fingerprint is the FNV-1a of the single byte 0x00, still with prefix kn1_ (see absentNoteStateId()).

Hosted canister: Approve does not recompute kn1_ in Motoko today (frontmatter serialization may differ from Node). Clients should rely on Node Hub for strict checks, or treat base_state_id as advisory on canister-only flows until parity is implemented.

external_ref on approve (optional Muse bridge)

Besides setting external_ref at POST /api/v1/proposals (create), operators may set or resolve it at POST /api/v1/proposals/:id/approve: the client can send external_ref in the approve body, or the server may fill it from an optional Muse lineage callback when MUSE_URL is configured. Approve never fails because Muse is unreachable. See MUSE-THIN-BRIDGE.md.

Optional fields (augmentation)

Field Purpose
intent Human- or agent-readable reason.
external_ref Optional cross-system id (e.g. Muse lineage).
labels String array for triage/filter (not only inside proposed frontmatter).
source e.g. agent, human, import.
suggested_labels, assistant_notes, assistant_model, assistant_at Tier-2 enrichment output when enabled.
review_queue Optional string for triage (e.g. legal), set by deterministic triggers or client.
review_severity standard or elevated, from triggers.
auto_flag_reasons String array of structured reason codes (e.g. phrase:…, path_prefix:…); audited on create when non-empty.
review_hints, review_hints_at, review_hints_model Optional async LLM text for humans only; never the sole merge gate.

Deterministic review triggers

Org-configurable rules in data/hub_proposal_review_triggers.json (override; packaged default hub/proposal-review-triggers-default.json) can force evaluation_status: pending and set review_queue / review_severity from:

  • literal_phrases — case-insensitive substring match on path + body + intent (bounded list/size per lib/hub-proposal-review-triggers.mjs).
  • path_prefixes — vault-relative path prefix match.
  • label_any — intersection with proposal labels.

Hosted: The gateway merges the same logic into POST /api/v1/proposals before the canister (see lib/hub-proposal-create-augment.mjs).

Human evaluation (Phase: proposal evaluation)

Evaluation is a human-led record (who/when/outcome/checklist/comment, optional grade). It is not the same as Tier-2 Enrich (LLM assist). LLM output must not be the sole merge authority.

evaluation_status (orthogonal to status)

Value Meaning
none No evaluation required for this proposal (gate off at creation), or legacy row with no field set.
pending Evaluation expected before approve (gate on at creation).
passed Evaluator recorded a pass outcome; approve allowed without waiver.
failed Evaluator recorded fail; approve blocked unless admin supplies a waiver (see below).
needs_changes Evaluator requested changes; approve blocked unless waiver.

Transitions (human action via POST /api/v1/proposals/:id/evaluation):

  • nonepassed | failed | needs_changes (optional audit when gate is off)
  • pendingpassed | failed | needs_changes
  • failed | needs_changespassed | failed | needs_changes (re-evaluation after edits)

approved / discarded proposals cannot receive new evaluations.

Stored fields (Node hub_proposals.json and canister ProposalRecord)

Field Purpose
evaluation_status One of the values above.
evaluation_grade Optional (e.g. letter or 1–5). Secondary to pass/fail.
evaluation_checklist JSON array: [{ "id", "label", "passed" }] merged from org rubric + submission.
evaluation_comment Free text; required for outcomes failed and needs_changes.
evaluated_by JWT sub of evaluator (v1: admin).
evaluated_at ISO timestamp.
evaluation_waiver Set on approve when bypassing a non-pass state: { "by", "at", "reason" }.

Gate: require evaluation before approve

Policy resolution (lib/hub-proposal-policy.mjs):

  • HUB_PROPOSAL_EVALUATION_REQUIRED=1 or true → gate on for new proposals.
  • =0 or false → gate off.
  • If unset: read data/hub_proposal_policy.json; if proposal_evaluation_required === true, gate on; else off.

When the gate is on, new proposals are created with evaluation_status: "pending" (unless triggers already implied pending). Approve is rejected with 403 / EVALUATION_REQUIRED unless:

  • evaluation_status === "passed", or
  • the approve request includes a non-empty waiver_reason (trimmed length ≥ 3), which records evaluation_waiver and an audit entry (approve_waiver).

When the gate is off at create, new proposals use evaluation_status: "none" unless review triggers force pending; admins may approve without submitting evaluation, but may still submit evaluation for audit.

Hosted canister: The gateway injects evaluation_status: "pending" on create when policy is on (same resolution using repo data/ beside the gateway). Approve rules on the canister are unchanged. Canister stores review_queue, review_severity, auto_flag_reasons_json, and optional review_hints (V3 ProposalRecord); upgrade migrates existing rows.

Rubric

Default checklist items ship in-repo (hub/proposal-rubric-default.json). Override with data/hub_proposal_rubric.json (same { "items": [{ "id", "label" }] } shape). See PROPOSAL-EVALUATION-RUBRIC-DEFAULT.md.

Who evaluates

Admins and evaluator users may POST …/evaluation. Approve defaults to admin; set HUB_EVALUATOR_MAY_APPROVE=1 to allow evaluator to approve. Discard remains admin on the Node Hub.

Optional LLM review hints

When KNOWTATION_HUB_PROPOSAL_REVIEW_HINTS=1, the Hub may asynchronously populate review_hints (self-hosted: after create; hosted: gateway schedules a canister POST …/review-hints after create). Prompt-injection: treat model output as untrusted; it does not change evaluation_status unless you add a separate policy (not shipped). Privacy: proposal body may be sent to OpenAI or Ollama per lib/llm-complete.mjs.

File History 2 commits
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor 1 day ago
sha256:9103f98c89257ed2b01c237cea895dabb3e85ea337dccb1161c175e4422355b6 docs: accept Calendar Events v0 spec with Phase 0 security … Human 1 day ago