v0.3.168 - Draft-Time Identity Hygiene + Honest Human Affirmation + Continuation Edges
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;--affirmis 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_idbuilds a new draft
id aszet_<day>_<time>_<slug>, whereslugis 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 theor "draft"fallback — producing a
misleadingzet_<ts>_draftid. The fallback token now becomesnote. This is
the ONLY change: the timestamp segments and thezet_..._slugshape 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; existingzet_<ts>_draftids (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…_noteand
…_note_2, two distinct inbox files. -
Attributed mint affirmation (Item 나). The two
needs_human_reviewchecklist
items (one_clear_purpose,sensitive_content_reviewed) arerequired: true
and, until now, could only be satisfied by hand-editing the draft's
mint.checklistYAML.mint-zetgains a repeatable--affirm <item_id>flag
(argparseaction="append", matching every other multi-value flag) plus a
required--reviewed-by. Affirmed ids are threaded through the whole dry-run
chain intobuild_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 labelcli_affirmation
(separate frommint_frontmatter,legacy_promotion_frontmatter,machine). The
mint receipt gains an attributedaffirmationsblock:{item_id, affirmed_by, affirmed_at}for each applied affirmation. Three mechanical gates hold:- Inert without an attributed reviewer.
--affirmwith no--reviewed-by
is a hard error (--affirm requires --reviewed-by …), so no affirmation is
ever recorded unattributed. - 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.). - Cannot override machine items.
object_id_only/allowed_edgesstay
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--affirmnever flips an explicit YAML
false.
Honest residual. Like the pre-existing
--reviewed-bygate,--affirmcannot
cryptographically prove the reviewer string names a real human. It introduces no
new self-affirm hole beyond the existing--reviewed-bytrust 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. - Inert without an attributed reviewer.
-
No silent auto-delete; discoverability pointer only (Item 다). Mint keeps
preserves_draft_reference: trueand never deletes the consumed inbox draft. A
successful mint result now carries anext_safe_actionslist with a single human
sentence pointing toarchive retire-draft --zettel-id <id> --dry-run, printed in
text mode as aNext:line. There is no opt-in chain flag in this release; any
future chain must run retire in--dry-runonly 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 concretesuggested_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
continuesedge type (Item 라). Acontinueslink type is added to the
base vocabulary in bothtypes.ymlfiles (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 — NOTderived_from(source/provenance), NOTreferences(topical
citation), NOTderived(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_TYPESandCONNECTION_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 owntypes.yml
will not receivecontinuesviamigrate link-types-v0.3; they add the entry
manually (it is additive). -
Draft-time
--kindvalidation +--list-kinds(Item 가).create-draft
validated nothing about--kindbefore writing it to frontmatter. It now resolves
the archive's ownnote_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 staysfleeting_capture, and no argparsechoices=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-kindsflag lists the archive's
valid note kinds and exits without writing (no--title/--bodyrequired).
JSON-contract additions (all additive)
- Mint receipt: a new
affirmationsarray (item_id,affirmed_by,affirmed_at),
empty when no affirmation was applied.mint-receipt.schema.jsonuses no
additionalProperties: false, so the field is additive and non-breaking. - Mint result: a new
next_safe_actionsstring 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.