@dzhechkov/harness-cli 0.7.5 → 0.7.6

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/.dz-manifest.json CHANGED
@@ -9,7 +9,7 @@
9
9
  },
10
10
  {
11
11
  "path": "README.md",
12
- "sha256": "bf6ac920e20f4e9978dbb7b1cca48790d97e44f245dc53088e189776b4a7616e"
12
+ "sha256": "ba98f7078023a6202a8bf809b83ae20ef44b3d2e1ca14ce0ae5aac83ffd8d51e"
13
13
  },
14
14
  {
15
15
  "path": "dist/bin.d.ts",
@@ -49,15 +49,15 @@
49
49
  },
50
50
  {
51
51
  "path": "dist/cli.d.ts.map",
52
- "sha256": "6fc728a98d8a920a226a4ee2d8b045ee46e27246c7d7e8bdf15e6c7758f3efbc"
52
+ "sha256": "3c0a60e8d8528e1b7df6bf5678388ce14d3ac3d0362bde42bc8e7e712d914dbd"
53
53
  },
54
54
  {
55
55
  "path": "dist/cli.js",
56
- "sha256": "4bc5e7cb6563fd672fd7e2c38eac4ba55d54de46940c194b3d2cd5ea4519732a"
56
+ "sha256": "f117e676f0a120e1314f3cc6416901931d9b389d97052985e1150fa75322b221"
57
57
  },
58
58
  {
59
59
  "path": "dist/cli.js.map",
60
- "sha256": "560d103ce98af8095eb7ee86537aa80de7a914fffa693dc23fdf2440a4f76183"
60
+ "sha256": "718f0380983cb995fad2a30b87af79feb3b0c85656449957bada67956e7e8854"
61
61
  },
62
62
  {
63
63
  "path": "dist/core-compat.d.ts",
@@ -113,15 +113,15 @@
113
113
  },
114
114
  {
115
115
  "path": "dist/known-flags.d.ts.map",
116
- "sha256": "23fa9b92489e2f39d99397a57f99a4c7566d41b75682d1bbde3f113c480acdcd"
116
+ "sha256": "93d7a002824ed631f1459e922ac2cad08772e06a21777b64eed095933dd0e889"
117
117
  },
118
118
  {
119
119
  "path": "dist/known-flags.js",
120
- "sha256": "f4ed9bddb45629484baf117a3b92eb4097932abda6e5a48227acbc7b5f23f561"
120
+ "sha256": "64928f5f20cc647f86323b4d179c614613635eeb6a553fd7733bf5ebad653d70"
121
121
  },
122
122
  {
123
123
  "path": "dist/known-flags.js.map",
124
- "sha256": "41bce9592c8192431f7f023271eaf3f548398e5c15441ea69a59e78633915cd9"
124
+ "sha256": "3cb9b072c57a3d9562cfb919c11c2b242db215169a4675b9940de46b67e0ccfa"
125
125
  },
126
126
  {
127
127
  "path": "keys/README.md",
@@ -133,7 +133,7 @@
133
133
  },
134
134
  {
135
135
  "path": "package.json",
136
- "sha256": "423120966d33fb4515177a7613f0ace5b392a576098987d0d9ca22aedea96716"
136
+ "sha256": "4831c7b0121cb2a62464bc4d4844e6037a80f9e2d1e6e0934836bde14a1bffdb"
137
137
  },
138
138
  {
139
139
  "path": "src/bin.ts",
@@ -145,7 +145,7 @@
145
145
  },
146
146
  {
147
147
  "path": "src/cli.ts",
148
- "sha256": "cae511b9b892c43e874ee06b439306290cd2c0a9e6b75cd0cd931d47adaef3f5"
148
+ "sha256": "f30fb7c6b0795758578a90de19b870c4cde42eb2009fa246051023f499374c09"
149
149
  },
150
150
  {
151
151
  "path": "src/core-compat.ts",
@@ -161,9 +161,9 @@
161
161
  },
162
162
  {
163
163
  "path": "src/known-flags.ts",
164
- "sha256": "aed996e8a3741b595eba31ef694ec5b2999dc0a73933a4289325cf6b9944e254"
164
+ "sha256": "b08dc5d28795419f642df56fbf5cd036a43a06bb1bec5e864f4e538b0a025b13"
165
165
  }
166
166
  ]
167
167
  },
168
- "signature": "DN7j3i23IeC8baQ4oOuoOiEPJMiyYF9/0XEVC7Du3p1QQgLZkJzdNQlHPVoUSGcmY57F5b9bn0K8tONFPTA3BQ=="
168
+ "signature": "az3T9G53JK8QzlVMBBMgoXLUN0Awpx4vfe19JJVYkbN67X5FDWUn8nVhe8IRAIKogxxbmp9lgnLkeYOj/b2YCg=="
169
169
  }
package/README.md CHANGED
@@ -1841,7 +1841,7 @@ dz recap [--day|--week|--month] [--at <ISO date>] [--refresh-publish
1841
1841
  dz cadence [--window day|week|month|quarter|halfyear|year] [--json] # the RHYTHM view of what shipped: graded-shipment counts bucketed by ISO week, npm-publish cadence (reads `dz recap`'s publish-times cache — run `dz recap --refresh-publishes` to warm it), guard repeat DECAY on the FIXED rule set (a rule joins only with pre-window history, so a newborn rule's zero is youth, not virtue — the no-stubs false-zero class excluded by construction), and recall reuse per week. A window deeper than 2× the record is REFUSED with the measured depth and the largest honest window named (a cadence from under two full windows is scale forgery). Sibling of `dz recap`: recap is the narrative what-was-done report over one window; cadence is the week-by-week rhythm across the window. exit 0 / 2 refused-window / 1 usage
1842
1842
  dz provenance-check --manifest <sources.json> [--project <dir>] [--json] # nothing goes out citing a source that may not leave this machine. Checks PROVENANCE, not words: every claim in a draft names its source, and a source is cleared only when it is a KNOWN kind that resolves safely. Repo paths are classified by `git -C <root> check-ignore` over the RESOLVED path — so a symlink into an ignored directory is refused, not cleared (MEASURED: git classifies the string and never dereferences), and the verdict does not change with your working directory. Store records need naming in the git-TRACKED `provenance-public.json`, so declaring one public is a reviewable commit rather than a field inside an ignored store. Anything else is refused: an undeclared kind is never inferred from the path's shape. exit 0 allowed / 1 blocked / 3 NOT ESTABLISHED — an empty manifest, an unreadable one, or an oracle that did not run is never a pass. **What it cannot do, said on the passing path too:** it proves what was CITED. It cannot see a paraphrase with no citation, nor confidential text pasted by hand into an allowed file. Read the draft.
1843
1843
  dz name-check [--command <n>] [--module <basename>] [--export <a,b>] [--project <dir>] [--json] # is this name free, BEFORE a line of code? Twice in one day a collision broke the build outright — `dz retro` was already a command, `decideProvenance` already an export — and both were answerable in advance. Scans workspace SOURCE and never `dist`, because a stale build answers 'free' confidently (MEASURED: half an hour of convincing live runs against a previous build while tsc was red). Checks a command name against the dispatcher AND the help block, a module basename against every package's src/, and exported identifiers against every declaration — naming the DECLARING file, not the barrel. exit 0 all free / 1 at least one taken / 2 nothing asked or the scan read nothing — an empty sweep is never a clean bill. **Honest limit, printed on the passing path:** it reads declarations, so a re-export under a different name stays the build's job.
1844
- dz tg-post --draft <file.html> [--manifest <sources.json>] [--channel <@name>] [--send --yes] [--night] [--json] # the sender for an APPROVED genai-tweets-channel post, held to the channel's own accepted ADRs: HTML mode only (never MarkdownV2 — 18 escapes against 3, one miss is a 400); link preview OFF by default (x.com previews in Telegram are broken since 2022); the 00:00-06:00 MSK quiet window refuses without an explicit --night. THE DEFAULT RUN IS A DRY-RUN: tag balance and allowed-tag checks, bare &/< detection, the 4096 visible-character limit with the overshoot counted — every issue named in one pass, not just the first. The provenance gate runs IN-PROCESS over --manifest, and a draft with no manifest is refused as unchecked when a send is asked. A real send needs --send AND --yes — ADR-004's standing order that publishing stays manual, stated out loud each time. The bot token (TELEGRAM_BOT_TOKEN or telegram.tokenFile) is never printed, and the gates run BEFORE any secret is read. exit 0 sent or clean dry-run / 1 refused / 2 usage
1844
+ dz tg-post --draft <file.html> [--manifest <sources.json>] [--channel <@name>] [--send --yes] [--night] [--max-per-day <n>] [--json] # the sender for an APPROVED genai-tweets-channel post, held to the channel's own accepted ADRs: HTML mode only (never MarkdownV2 — 18 escapes against 3, one miss is a 400); link preview OFF by default (x.com previews in Telegram are broken since 2022); the 00:00-06:00 MSK quiet window refuses without an explicit --night. THE DEFAULT RUN IS A DRY-RUN: tag balance and allowed-tag checks, bare &/< detection, the 4096 visible-character limit with the overshoot counted — every issue named in one pass, not just the first. The provenance gate runs IN-PROCESS over --manifest, and a draft with no manifest is refused as unchecked when a send is asked. A real send needs --send AND --yes — ADR-004's standing order that publishing stays manual, stated out loud each time. Three autopublish guards run FAIL-CLOSED, in a fixed order: the **stop-cord** (`.dz/tg-post/HALT` exists ⇒ nothing publishes, checked FIRST so no bug in a later gate can route around it), **dedup** by the sha256 of the post's VISIBLE text (what the reader sees, not the bytes — a whitespace-different draft is the same post), and the **daily limit** (10 by default, `--max-per-day <n>` to change it), counted over the trailing 24h. The journal is two-phase: a `pending` row is written BEFORE the network call and a `sent` row after Telegram accepts, so a crash between the two is caught by dedup on the next run instead of double-publishing; only `sent` rows eat the daily ceiling. An UNREADABLE journal REFUSES — an unreadable counter does not prove the ceiling is unreached. The provenance gate also clears `kind: url`: a well-formed http(s) URL is public by construction so there is nothing local to protect, while a `file://`, a bare path or a non-URL is refused, never inferred. The bot token (TELEGRAM_BOT_TOKEN or telegram.tokenFile) is never printed, and the gates run BEFORE any secret is read. exit 0 sent or clean dry-run / 1 refused / 2 usage
1845
1845
  dz feature-adr-checkpoint (--slug <feature> | --feature-dir <abs>) --stage <s> --input-hash <h> --result <json> [--artifact a,b] [--json]
1846
1846
  dz reqe [--slug <feature> [--done --report <f>]] [--project <dir>] [--json] # the re-QE debt ledger: a usage-switched feature-adr run whose Step-8 QE ran on the coder's OWN family (cross-model guard suspended, FR-2.9) records a debt; list debts (also surfaced by dz usage), print the cross-family review brief, settle FAIL-CLOSED against an existing GRADED report (the run's own 08_qe_report.md — even hard-linked — can never settle its own debt); settlement lands in 08_qe_report.md, evidence rotates to reqe-settled.json
1847
1847
  dz qe-bridge --family claude --slug <feature> [--coder-family codex|claude] [--model <id>] [--files a,b] [--out <f>] [--timeout <s>] [--allow-same-family] [--json] # the REVERSE QE bridge (Codex-hosted → Claude reviewer): the reviewer runs ISOLATED (an empty temp cwd + --safe-mode --strict-mcp-config --tools '' --no-session-persistence, so no CLAUDE.md/skills/plugins/hooks/MCP load) and its verdict is read from the --output-format json RESULT ENVELOPE, so text a customization printed onto the same stdout can never become a signoff. Probes the model first; sends SCOPED extracts under a loud 200k-char ceiling; the grade must agree across three LAST-anchored channels AND the marker must be the final content — empty/gradeless/mismatched/miscounted output is a named failure with an audit record under features/<slug>/.fa-state/qe-bridge/, never a clean review. exit 0 signoff parsed (ANY grade — it reports, it does not gate) / 1 named failure / 2 usage. DZ_QE_BRIDGE_CLAUDE_BIN is a TEST SEAM (recorded as binOverride:true)
@@ -4096,10 +4096,38 @@ npx @dzhechkov/p-replicator init
4096
4096
 
4097
4097
  ## Status
4098
4098
 
4099
- `v0.7.5` — **a signature-only republish.** `0.7.0` shipped through `pnpm publish` rather than
4099
+ `v0.7.6` — **`dz drift-check` and `dz sync-canonical` stop being a `.claude/skills` gate.** Skill-copy
4100
+ discovery searched `packages/` plus one hardcoded install root, so the four other per-target install
4101
+ trees were ungated — measurably: this repo's own Codex install of `feature-adr` under `.agents/skills`
4102
+ drifted for a day while `dz sync-canonical feature-adr --check` reported "all 3 copies match
4103
+ canonical" and the HARD `no-skill-drift` rule passed. The copy was missing both the K1 section of its
4104
+ `SKILL.md` and the C6 check of its gate script. Discovery is now driven by a target→install-root
4105
+ registry, and the HARD rule runs at a new scope covering generated installs while exempting the
4106
+ hand-edited dev tree (which legitimately lags — three real skills drift there today, so gating it
4107
+ would be red-on-arrival). **The guard legitimately gets STRICTER: a publish that passed before can now
4108
+ be BLOCKED by real drift in a non-`.claude` root — that is the gate working.** Target enrichment
4109
+ written by `dz init --enrich` is exempt from both the drift verdict and the healer, so `sync-canonical`
4110
+ cannot delete it. Also: `dz tg-post` gains `--max-per-day`, previously read by the code but
4111
+ unregistered.
4112
+
4113
+ `v0.7.6` — **the channel sender stops trusting itself.** `dz tg-post` could format-check, provenance-check
4114
+ and time-check a post and still publish it twice, or ten more times, or right through an operator who
4115
+ wanted everything stopped: nothing counted what had already gone out. It now runs three guards FAIL-CLOSED
4116
+ in a fixed order — a **stop-cord** file that halts even a perfect post before any cheaper check, **dedup**
4117
+ keyed on the sha256 of the post's VISIBLE text rather than its bytes, and a **daily limit** (10 by default,
4118
+ `--max-per-day <n>`) counted over the trailing 24h. The send journal is two-phase — `pending` written before
4119
+ the network call, `sent` after Telegram accepts — so a crash in that window is caught by dedup instead of
4120
+ double-publishing, and only accepted sends eat the ceiling. An unreadable journal refuses: an unreadable
4121
+ counter does not prove the ceiling is unreached. The provenance gate additionally clears `kind: url` — a
4122
+ well-formed http(s) URL is public by construction, while a `file://`, a bare path or a non-URL is refused
4123
+ and never inferred from its shape. Also: `dz challenge` is now discoverable from the CLI's own help surface
4124
+ (it existed and was reachable only if you already knew the name), and the adversary it assembles is fed all
4125
+ five calibration documents rather than a subset.
4126
+
4127
+ `v0.7.6` — **a signature-only republish.** `0.7.0` shipped through `pnpm publish` rather than
4100
4128
  `dz publish`, so the re-signing step was skipped and 17 of 497 files in the published core did not
4101
4129
  match their signed hashes — the content was correct, the manifest was ten hours stale. Nothing in
4102
- the shipped behaviour changes between `0.7.0` and `0.7.5`; the integrity check stops reporting these
4130
+ the shipped behaviour changes between `0.7.0` and `0.7.6`; the integrity check stops reporting these
4103
4131
  packages as tampered. The one code change is a TEST: the compat case that asserted the workspace
4104
4132
  core sits exactly on `MIN_CORE` is split into an integration half and a boundary half, so a patch
4105
4133
  bump of core no longer reddens it and `MIN_CORE` need not claim a version the CLI does not require.
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -26,7 +26,7 @@ readBacklogConfig, readIdeas, writeIdeas, ideaId, dedupIdea, readGoalMap, readGo
26
26
  // qe-bridge (feature qe-bridge-claude, ADR-001): the pure half of the reverse QE bridge.
27
27
  KNOWN_CLAUDE, isSafeClaudeId, claudeProbeArgs, claudeReviewArgs, interpretClaudeProbe, modelFamily, buildBridgePrompt, parseBridgeOutput, buildBridgeFailureRecord, buildBridgeSignoffRecord, renderBridgeReport, isSafeSlug, hasUnsafePathChars, hasDotDotSegment, buildReqeBrief, settleReqeDebt, renderReqeList, REQE_SCOPE,
28
28
  // Mutation gate (feature ha-mutation-gate) — break each named protection, run the suite, require red.
29
- parseMutationRegistry, applyMutationToText, countFailingTests, classifyBaseline, classifyRunFailure, classifyMutationOutcome, mutationGateExitCode, summarizeMutationResults, renderMutationReport, TRACE_BUNDLE_LEDGER_PATH, TRACE_BUNDLE_SCHEMA, TRACE_BUNDLE_RUN_META_FILE, buildBundle, serializeBundle, parseBundle, planImport, decideCheckpointWrite, amendmentSection, planSaysNoAmendments, parseAmendments, resolveAmendments, decideAmendmentOutcome, amendmentVerdictLine, amendmentsMissingFromPlan, AMENDMENT_VACUITY_NOTE, decideSignableSet, signableSetLine, decideRecordWrite, decideReadBack, recordVerdictLine, buildCadenceReport, CADENCE_WINDOW_DAYS, } from '@dzhechkov/harness-core';
29
+ parseMutationRegistry, applyMutationToText, countFailingTests, classifyBaseline, classifyRunFailure, classifyMutationOutcome, mutationGateExitCode, summarizeMutationResults, renderMutationReport, TRACE_BUNDLE_LEDGER_PATH, TRACE_BUNDLE_SCHEMA, TRACE_BUNDLE_RUN_META_FILE, buildBundle, serializeBundle, parseBundle, planImport, decideCheckpointWrite, amendmentSection, planSaysNoAmendments, parseAmendments, resolveAmendments, decideAmendmentOutcome, amendmentVerdictLine, amendmentsMissingFromPlan, AMENDMENT_VACUITY_NOTE, decideSignableSet, signableSetLine, decideRecordWrite, decideReadBack, recordVerdictLine, buildCadenceReport, tgVisibleSha256, CADENCE_WINDOW_DAYS, } from '@dzhechkov/harness-core';
30
30
  import { getPreset, PRESET_NAMES } from '@dzhechkov/harness-presets';
31
31
  import { scanGitHub, analyzeRepo, generateReport, deepAnalyze, scanAllSources, ScoutMemory } from '@dzhechkov/scout';
32
32
  const USAGE = `dz - DZ cross-platform harness CLI
@@ -59,6 +59,7 @@ Usage:
59
59
  dz release [--filter <name>] [--tag] [--publish] [--json] [--dry-run] [--no-issue] (VERIFIED release: 4 HARD gates in FRONT of dz publish — full package test suites, audit >=high, node --check of every dist/bin file, bin smoke-boot via "node <bin> --help" — any red gate STOPS the release (exit 1) + best-effort gh issue; all green ⇒ re-sign reminder, then prints the ready dz publish command (or chains with --publish); never duplicates publish's own gates)
60
60
  dz parity [--target <name>] [--json] (the honest feature×target map, COMPUTED from the capability model — which harness feature is full / manual / absent on each of the ${TARGET_NAMES.length} targets, and via which form)
61
61
  dz delivery-check --slug <slug> [--context-only] [--findings <f.json>] [--strict] [--author <model>] [--json] (portable Step-10 Delivery Gate: prints the 4-plane review brief + artifact probes; --findings classifies a fed-back review into a fail-closed ready|blocked hand-off and writes features/<slug>/10_delivery_review.md; --strict exits 1 on blocked)
62
+ dz challenge --plan <plan.md> [--author <model>] (the deterministic cartridge behind the challenge-panel adversarial plan-gate (R6): assembles the wide brief — plan + architecture/vision.md + testing.md + map.json + degradations.md — and prints the C1-C8 adversary prompt naming the cross-family reviewer to dispatch. exit 0 brief printed / 1 plan missing or empty)
62
63
  dz skills-verify [--dir <project>] [--expect a,b] [--static] [--strict] [--json] (does .claude/skills/ actually REGISTER? --static = instant layout scan for CI; default reads the authoritative system/init listing from a real session. exit 0 pass / 1 fail / 2 inconclusive — never a false pass)
63
64
  dz compounding [--project <dir>] [--json] (honest learning-loop payoff report: pool write-only ratio, guard repeat-violation trajectory, cold-vs-warm replay readiness, instrumentation health — a gate without enough data says INSUFFICIENT_DATA, never a fake verdict)
64
65
  dz epoch-replay --mock [--n <N>] [--effect <-1..1>] [--tie-rate <0..1>] [--seed <N>] [--slice <name>] [--json] ($0 synthetic run — exercises the verdict math, NOT evidence)
@@ -6708,7 +6709,7 @@ function gatherGuardFacts(op, root, text, storeCap) {
6708
6709
  }
6709
6710
  catch { /* unreadable tree — the rule reports nothing rather than inventing a violation */ }
6710
6711
  try {
6711
- facts['drift'] = sweepSkillDrift(root, { scope: 'packages', allowlist: readDriftAllowlist(root) }).drifted.map((d) => d.name);
6712
+ facts['drift'] = sweepSkillDrift(root, { scope: 'installs', allowlist: readDriftAllowlist(root) }).drifted.map((d) => d.name);
6712
6713
  }
6713
6714
  catch { /* skip */ }
6714
6715
  facts['counts'] = gatherReadmeCounts(root);
@@ -6911,7 +6912,7 @@ function gatherGuardFacts(op, root, text, storeCap) {
6911
6912
  }
6912
6913
  if (op === 'consolidate') {
6913
6914
  try {
6914
- facts['drift'] = sweepSkillDrift(root, { scope: 'packages', allowlist: readDriftAllowlist(root) }).drifted.map((d) => d.name);
6915
+ facts['drift'] = sweepSkillDrift(root, { scope: 'installs', allowlist: readDriftAllowlist(root) }).drifted.map((d) => d.name);
6915
6916
  }
6916
6917
  catch { /* skip */ }
6917
6918
  }
@@ -10156,12 +10157,42 @@ async function cmdTgPost(options, flags, cwd, write) {
10156
10157
  for (const line of renderSourceProvenance(decision))
10157
10158
  write(line);
10158
10159
  }
10160
+ // ADR-005 autopublish guards: read the stop-cord and the send journal as FACTS, then let the pure
10161
+ // decideTgSend judge. An UNREADABLE journal stays undefined ⇒ decideTgSend fails closed on G4/G5.
10162
+ const tgDir = join(repoRoot, '.dz', 'tg-post');
10163
+ const halted = existsSync(join(tgDir, 'HALT'));
10164
+ const sha256 = tgVisibleSha256(draft);
10165
+ let sentLog;
10166
+ const sentLogPath = join(tgDir, 'sent-log.jsonl');
10167
+ if (!existsSync(sentLogPath)) {
10168
+ sentLog = []; // no journal yet is an EMPTY journal, not an unreadable one — a fresh channel sends
10169
+ }
10170
+ else {
10171
+ try {
10172
+ sentLog = [];
10173
+ for (const line of readFileSync(sentLogPath, 'utf-8').split('\n')) {
10174
+ if (line.trim() === '')
10175
+ continue;
10176
+ const r = JSON.parse(line);
10177
+ if (typeof r.sha256 === 'string' && typeof r.ts === 'string') {
10178
+ sentLog.push({ sha256: r.sha256, ts: r.ts, ...(r.status === 'pending' || r.status === 'sent' ? { status: r.status } : {}) });
10179
+ }
10180
+ }
10181
+ }
10182
+ catch {
10183
+ sentLog = undefined; // genuinely unreadable ⇒ fail-closed
10184
+ }
10185
+ }
10159
10186
  const decision = decideTgSend({
10160
10187
  issues,
10161
10188
  provenanceOutcome,
10162
10189
  confirmed: flags.has('send') && flags.has('yes'),
10163
10190
  nowUtcIso: new Date().toISOString(),
10164
10191
  nightOverride: flags.has('night'),
10192
+ halted,
10193
+ sha256,
10194
+ sentLog,
10195
+ maxPostsPerDay: (() => { const n = Number(options.get('max-per-day')); return Number.isFinite(n) && n > 0 ? n : 10; })(),
10165
10196
  });
10166
10197
  const visible = tgVisibleLength(draft);
10167
10198
  if (!json) {
@@ -10184,6 +10215,17 @@ async function cmdTgPost(options, flags, cwd, write) {
10184
10215
  write('dz tg-post: --channel @name (or a chat id) is required to send');
10185
10216
  return 2;
10186
10217
  }
10218
+ // Two-phase journal (Codex A-): write a PENDING row BEFORE the network call. If the process dies
10219
+ // between send and the sent-row, G5 dedup sees this pending row on the next run and refuses to
10220
+ // double-publish. Best-effort — a pending-write failure is warned, not fatal (better to risk one
10221
+ // duplicate than to block a legitimate send on a full disk).
10222
+ try {
10223
+ mkdirSync(tgDir, { recursive: true });
10224
+ appendFileSync(sentLogPath, JSON.stringify({ sha256, ts: new Date().toISOString(), channel, status: 'pending' }) + '\n');
10225
+ }
10226
+ catch (e) {
10227
+ write(`dz tg-post: WARNING — could not write the PENDING journal row (${e.message}); the crash-window dedup guard is degraded for this send`);
10228
+ }
10187
10229
  const sent = await tgApi(token, 'sendMessage', {
10188
10230
  chat_id: channel,
10189
10231
  text: draft,
@@ -10197,6 +10239,16 @@ async function cmdTgPost(options, flags, cwd, write) {
10197
10239
  write(JSON.stringify({ ok: false, action: 'send', reason: sent.description ?? 'refused', visible }));
10198
10240
  return 1;
10199
10241
  }
10242
+ // Record the send AFTER Telegram accepted it (never before — a failed send must not eat the daily
10243
+ // limit or block a retry via dedup). Best-effort append; a journal write failure is logged, not
10244
+ // fatal — the post already went out.
10245
+ try {
10246
+ mkdirSync(tgDir, { recursive: true });
10247
+ appendFileSync(sentLogPath, JSON.stringify({ sha256, ts: new Date().toISOString(), channel, messageId: sent.messageId ?? null, status: 'sent' }) + '\n');
10248
+ }
10249
+ catch (e) {
10250
+ write(`dz tg-post: WARNING — sent, but could not record it in ${sentLogPath} (${e.message}) — the daily limit and dedup may under-count until fixed`);
10251
+ }
10200
10252
  write(`dz tg-post: sent to ${channel}${sent.messageId !== undefined ? ` (message ${sent.messageId})` : ''}`);
10201
10253
  if (json)
10202
10254
  write(JSON.stringify({ ok: true, action: 'send', channel, messageId: sent.messageId ?? null, visible }));