Skip to content

v0.3.168 - Draft-Time Identity Hygiene + Honest Human Affirmation + Continuation Edges

Choose a tag to compare

@mow-coding mow-coding released this 04 Jul 10:47

v0.3.168 - Draft-Time Identity Hygiene + Honest Human Affirmation + Continuation Edges

v0.3.168 sharpens three lifecycle safety edges without loosening any of them:
new draft ids stop carrying a misleading _draft slug, the mint human-review
checklist can finally be satisfied by an attributed, auditable CLI act instead
of a raw YAML hand-edit, and a continues edge type gives same-thread follow-on a
first-class home. Five changes ship together. Every one is additive: no archive
migration, no id rewrite, no hash change, all flags opt-in.

Prime directives (unchanged)

Identity safety — forward-only. No existing canonical id is ever renamed or
normalized; mint gains no id-rewrite path. Only the generator of new draft ids
changes, before any reference can exist.

Lifecycle safety — no silent auto-delete. Mint never deletes the consumed
inbox draft. Retirement stays its own approval-gated step.

Lifecycle safety — no AI self-affirm. A human-review checklist item can only
be affirmed with an attributed --reviewed-by; --affirm is inert without one,
cannot override machine-enforced items, and is recorded auditably in the receipt.

What ships

  • Draft-id hygiene, forward-only (Item 마). make_zettel_id builds a new draft
    id as zet_<day>_<time>_<slug>, where slug is the title reduced to
    [a-z0-9_]. A titleless title, or a pure-Hangul title (no ASCII alphanumerics),
    reduces to an empty slug and hit the or "draft" fallback — producing a
    misleading zet_<ts>_draft id. The fallback token now becomes note. This is
    the ONLY change: the timestamp segments and the zet_..._slug shape are
    untouched, and the fix runs once at draft creation, before any reference target
    exists
    (canonical id/filename, edges, source_refs, object manifests, the
    mint receipt path, the draft snapshot path all derive from the id only later, at
    mint). No existing id is renamed; existing zet_<ts>_draft ids (and real title
    slugs that happen to contain the word "draft") are untouched. The same-second
    collision loop is unchanged, so two titleless drafts become …_note and
    …_note_2, two distinct inbox files.

  • Attributed mint affirmation (Item 나). The two needs_human_review checklist
    items (one_clear_purpose, sensitive_content_reviewed) are required: true
    and, until now, could only be satisfied by hand-editing the draft's
    mint.checklist YAML. mint-zet gains a repeatable --affirm <item_id> flag
    (argparse action="append", matching every other multi-value flag) plus a
    required --reviewed-by. Affirmed ids are threaded through the whole dry-run
    chain into build_lifecycle_checklist, where — only when the operator did not
    hand-edit the YAML
    (explicit is None) and the id is one of the two human items
    — the item is marked passed with a distinct source label cli_affirmation
    (separate from mint_frontmatter, legacy_promotion_frontmatter, machine). The
    mint receipt gains an attributed affirmations block: {item_id, affirmed_by, affirmed_at} for each applied affirmation. Three mechanical gates hold:

    1. Inert without an attributed reviewer. --affirm with no --reviewed-by
      is a hard error (--affirm requires --reviewed-by …), so no affirmation is
      ever recorded unattributed.
    2. Scoped. The service accepts affirmed ids only for the two human-review
      items; any other id is rejected (--affirm only accepts human-review items: one_clear_purpose, sensitive_content_reviewed.).
    3. Cannot override machine items. object_id_only / allowed_edges stay
      machine-blocked: they are excluded from the affirmable set AND the
      machine-enforced-blocked branch precedes the affirmation branch, so a machine
      block is unreachable-to-flip.
      A YAML hand-edit still wins first, so --affirm never flips an explicit YAML
      false.

    Honest residual. Like the pre-existing --reviewed-by gate, --affirm cannot
    cryptographically prove the reviewer string names a real human. It introduces no
    new self-affirm hole
    beyond the existing --reviewed-by trust boundary; it only
    guarantees (a) no affirmation is recorded without an attributed reviewer and (b)
    the affirmation is auditable in the receipt. We deliberately do NOT add an
    ai_runtime: / ai:-prefix rejection: it would be trivially bypassed
    (--reviewed-by person:not-really), giving false assurance, and would break the
    legitimate audited case where an operator's id carries a tool tag. Auditability,
    not string-sniffing, is the honest guarantee.

  • No silent auto-delete; discoverability pointer only (Item 다). Mint keeps
    preserves_draft_reference: true and never deletes the consumed inbox draft. A
    successful mint result now carries a next_safe_actions list with a single human
    sentence pointing to archive retire-draft --zettel-id <id> --dry-run, printed in
    text mode as a Next: line. There is no opt-in chain flag in this release; any
    future chain must run retire in --dry-run only or demand its own --approve +
    --reviewed-by, never deleting the draft implicitly. The doctor's existing INFO
    prose (minted_inbox_draft_twin_pending_retire) is left unchanged — info() /
    warn() cannot carry a concrete suggested_command, and extending them is
    out-of-scope cross-cutting work; the mint-time pointer routes the operator at the
    exact moment the stale draft is created.

  • Base continues edge type (Item 라). A continues link type is added to the
    base vocabulary in both types.yml files (the KIT base and the fake-archive test
    fixture). Semantics are carved away from every overlapping neighbor: continues
    means a same-thread continuation / next installment in the SAME line of thought
    or work
    — NOT derived_from (source/provenance), NOT references (topical
    citation), NOT derived (a distinct later product built from this zet), NOT
    supersedes (replacing an older version), and NOT a generic ordered process step
    (sequence). It is deliberately NOT added to
    CONNECTION_IMPORT_RECOMMENDED_EDGE_TYPES and CONNECTION_EDGE_RELATIONSHIP_VOCABULARY
    is left untouched, because migration/revert only ever touch the recommended set —
    so a base-only member keeps every pinned migration and connection-vocabulary test
    green. Acknowledged limitation: archives that vendored their own types.yml
    will not receive continues via migrate link-types-v0.3; they add the entry
    manually (it is additive).

  • Draft-time --kind validation + --list-kinds (Item 가). create-draft
    validated nothing about --kind before writing it to frontmatter. It now resolves
    the archive's own note_kind_rules(load_zettel_rules(root)) and, if the kind is
    unknown, appends a WARNING (not a blocker) that names the kind and enumerates
    the valid kind ids — consistent with mint, which only warns on unknown kinds. The
    default stays fleeting_capture, and no argparse choices= is added (valid kinds
    are archive-owned and may be custom; choices= is fixed before the archive root
    is known and would be stricter than mint). The warning is now printed in the
    non-dry-run text path too. A read-only --list-kinds flag lists the archive's
    valid note kinds and exits without writing (no --title / --body required).

JSON-contract additions (all additive)

  • Mint receipt: a new affirmations array (item_id, affirmed_by, affirmed_at),
    empty when no affirmation was applied. mint-receipt.schema.json uses no
    additionalProperties: false, so the field is additive and non-breaking.
  • Mint result: a new next_safe_actions string list.

Test honesty note

New tests use temp-dir fixtures copied from the fake-life archive and never touch a
real archive. They pin: unknown-kind warns-not-blocks and lists valid kinds;
--list-kinds writes nothing; affirm mints without a YAML edit; affirm inert
without a reviewer; the receipt affirmations attribution and the cli_affirmation
source label; affirm cannot override object_id_only; the next_safe_actions
retire pointer; a continues edge is writable AND migrate link-types-v0.3
dry-run/approve/revert stay green; and a titleless / pure-Hangul draft gets a
_note id with two same-second drafts distinct, while an existing zet_<ts>_draft
fixture id is untouched.

Safety and scope

No archive migration. No id rewrite — existing canonical ids are unchanged. No hash
change. --affirm's honest residual is stated above: it guarantees attribution and
auditability, not proof of humanity. continues is base-only and reaches vendored
types.yml archives only by a manual, additive edit. All new flags are opt-in.

Upgrade

See UPGRADE.md. All changes are additive; no migration is required.