@codedrifters/configulator 0.0.402 → 0.0.403

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/lib/index.mjs CHANGED
@@ -4326,6 +4326,35 @@ function buildBaseBundle(paths = DEFAULT_AGENT_PATHS) {
4326
4326
  "schema and consumer example. `status:deferred` is a valid",
4327
4327
  "override value reserved for this exact use case.",
4328
4328
  "",
4329
+ "### The `status:deferred` invariant",
4330
+ "",
4331
+ "**No agent, procedure, or sweep ever removes `status:deferred`.",
4332
+ "Only a human promotes a deferred issue.**",
4333
+ "",
4334
+ "`status:deferred` records a deliberate human decision to park",
4335
+ "work. Automation may read it, count it, and log it \u2014 but the",
4336
+ "label is cleared exclusively by a human (or by a scheduled task",
4337
+ "a human configured for that purpose). Concretely:",
4338
+ "",
4339
+ "- **Unblock sweeps skip it.** Both `check-blocked.sh unblock`",
4340
+ " and `unblock-dependents.sh` leave a `status:deferred` +",
4341
+ " `status:blocked` issue blocked when its dependencies close,",
4342
+ " emitting a `SKIP_DEFERRED #<n>` line instead of flipping to",
4343
+ " `status:ready`. Dependency resolution is not a promotion",
4344
+ " signal for parked work.",
4345
+ "- **Dispatch scans exclude it.** `check-blocked.sh eligible`",
4346
+ " drops any issue carrying `status:deferred`, so a stray",
4347
+ " `status:ready` + `status:deferred` pairing never reaches a",
4348
+ " worker.",
4349
+ "- **No sweep writes it either.** Automation adds",
4350
+ " `status:deferred` only at filing time via the configured",
4351
+ " `issueDefaults` \u2014 never as a runtime triage decision.",
4352
+ "",
4353
+ "An issue that legitimately needs to leave the parked backlog is",
4354
+ "promoted by a human removing `status:deferred` and setting the",
4355
+ "appropriate base status. Any automation that removes the label",
4356
+ "is a bug.",
4357
+ "",
4329
4358
  "### Blocking Rules",
4330
4359
  "",
4331
4360
  "Two rules force `status:blocked` \u2014 both are non-negotiable:",
@@ -14818,13 +14847,16 @@ function renderUnblockDependentsSection(ud) {
14818
14847
  "",
14819
14848
  "1. Searches open issues for `Depends on: #<closed>` references in",
14820
14849
  " their body.",
14821
- "2. For each match, re-reads every dependency listed across",
14850
+ "2. Skips any match carrying `status:deferred`, emitting a",
14851
+ " `SKIP_DEFERRED` line. A human-parked issue is never promoted by",
14852
+ " a sweep, no matter how its dependencies resolve.",
14853
+ "3. For each remaining match, re-reads every dependency listed across",
14822
14854
  " **all** `Depends on:` lines in the body (bodies routinely list",
14823
14855
  " one dependency per line) and checks whether they are all closed.",
14824
- "3. If **all** dependencies are closed, flips the dependent from",
14856
+ "4. If **all** dependencies are closed, flips the dependent from",
14825
14857
  " `status:blocked` to `status:ready` and posts a one-line comment",
14826
14858
  " citing the resolving issue.",
14827
- "4. If **some** dependencies are still open, leaves the dependent",
14859
+ "5. If **some** dependencies are still open, leaves the dependent",
14828
14860
  " as `status:blocked` and optionally posts a partial-unblock",
14829
14861
  " comment (see the **Partial unblock behaviour** subsection",
14830
14862
  " below).",
@@ -14858,6 +14890,7 @@ function renderUnblockDependentsSection(ud) {
14858
14890
  'UNBLOCKED #<dep> \u2014 all deps closed (<closed-list>) \u2014 "<title>"',
14859
14891
  'UNBLOCK_FAILED #<dep> \u2014 label flip failed (all deps closed: <closed-list>) \u2014 "<title>"',
14860
14892
  'STILL_BLOCKED #<dep> \u2014 waiting on <open-list> \u2014 "<title>"',
14893
+ 'SKIP_DEFERRED #<dep> \u2014 status:deferred; human-parked, not promoting \u2014 "<title>"',
14861
14894
  "NO_DEPENDENTS #<closed>",
14862
14895
  "```",
14863
14896
  "",
@@ -14867,7 +14900,10 @@ function renderUnblockDependentsSection(ud) {
14867
14900
  "error, permissions, or the dependent went stale between the",
14868
14901
  "search and the edit) \u2014 a human needs to retry or flip the label",
14869
14902
  "manually. `STILL_BLOCKED` lines mean the dependent stays blocked",
14870
- "pending other open deps. `NO_DEPENDENTS` means no open issue",
14903
+ "pending other open deps. `SKIP_DEFERRED` lines mean the dependent",
14904
+ "carries `status:deferred` and was deliberately left blocked even",
14905
+ "though its dependencies resolved \u2014 the sweep never promotes a",
14906
+ "human-parked issue. `NO_DEPENDENTS` means no open issue",
14871
14907
  "references the just-closed issue in a `Depends on:` line.",
14872
14908
  "",
14873
14909
  "### Partial unblock behaviour",
@@ -15018,7 +15054,7 @@ function renderUnblockDependentsScript(ud) {
15018
15054
  "# `status:blocked` \u2192 `status:ready` directly on the overflow.",
15019
15055
  'dependents=$(gh issue list --label "status:blocked" --state open \\',
15020
15056
  ' --search "in:body \\"Depends on:\\"" \\',
15021
- ' --json number,title,body --limit 100 2>/dev/null || echo "[]")',
15057
+ ' --json number,title,body,labels --limit 100 2>/dev/null || echo "[]")',
15022
15058
  "",
15023
15059
  `count=$(echo "$dependents" | jq 'length')`,
15024
15060
  'if [[ "$count" -eq 0 ]]; then',
@@ -15026,6 +15062,18 @@ function renderUnblockDependentsScript(ud) {
15026
15062
  " exit 0",
15027
15063
  "fi",
15028
15064
  "",
15065
+ "# Human-parked candidates (`status:deferred`). Collected jq-side into a",
15066
+ "# space-delimited lookup string rather than threaded through the",
15067
+ "# tab-separated records below: an extra TSV field would either sit after",
15068
+ "# dep_line (displacing the mandatory-last optional field) or before it",
15069
+ "# (reintroducing the #884 IFS tab-collapse bug). The skip itself happens",
15070
+ "# inside the loop, after the closed-issue reference test, so an unrelated",
15071
+ "# deferred issue in the search window never emits a line. No agent or",
15072
+ "# sweep ever removes `status:deferred` \u2014 only a human promotes it.",
15073
+ `deferred_set=" $(echo "$dependents" | jq -r '`,
15074
+ ' .[] | select(.labels | map(.name) | index("status:deferred")) | .number',
15075
+ `' | tr '\\n' ' ')"`,
15076
+ "",
15029
15077
  "# Union every `Depends on:` line per candidate (a body may list one",
15030
15078
  "# dependency per line) into a single space-joined dep string and stream",
15031
15079
  "# as tab-separated number / title / dep-line tuples.",
@@ -15061,6 +15109,14 @@ function renderUnblockDependentsScript(ud) {
15061
15109
  "",
15062
15110
  " found_any=true",
15063
15111
  "",
15112
+ " # Deliberately-parked dependents never get promoted by a sweep, even",
15113
+ " # when every dependency has closed. Only a human clears",
15114
+ " # `status:deferred`.",
15115
+ ' if [[ "$deferred_set" == *" ${num} "* ]]; then',
15116
+ ' echo "SKIP_DEFERRED #${num} \u2014 status:deferred; human-parked, not promoting \u2014 \\"${title}\\""',
15117
+ " continue",
15118
+ " fi",
15119
+ "",
15064
15120
  " # Re-check every dep in the list. Fully-closed \u2192 unblock.",
15065
15121
  " all_closed=true",
15066
15122
  ' open_deps=""',
@@ -15250,15 +15306,26 @@ function buildCheckBlockedScript(tiers, scopeGate, _runRatio) {
15250
15306
  " # position.",
15251
15307
  " local issues",
15252
15308
  ' issues=$(gh issue list --label "status:blocked" --state open \\',
15253
- ' --json number,body --limit 1000 2>/dev/null || echo "[]")',
15309
+ ' --json number,body,labels --limit 1000 2>/dev/null || echo "[]")',
15254
15310
  "",
15255
15311
  " local count",
15256
15312
  ` count=$(echo "$issues" | jq 'length')`,
15257
15313
  ' if [[ "$count" -eq 0 ]]; then',
15258
- ' echo "TRIAGE_DONE unblocked=0 still_blocked=0"',
15314
+ ' echo "TRIAGE_DONE unblocked=0 still_blocked=0 deferred_skipped=0"',
15259
15315
  " return 0",
15260
15316
  " fi",
15261
15317
  "",
15318
+ " # Human-parked candidates (`status:deferred`). Collected jq-side into",
15319
+ " # a space-delimited lookup string rather than threaded through the",
15320
+ " # tab-separated records below: an extra TSV field would either sit",
15321
+ " # after dep_line (displacing the mandatory-last optional field) or",
15322
+ " # before it (reintroducing the #884 IFS tab-collapse bug). No agent",
15323
+ " # or sweep ever removes `status:deferred` \u2014 only a human promotes it.",
15324
+ " local deferred_set",
15325
+ ` deferred_set=" $(echo "$issues" | jq -r '`,
15326
+ ' .[] | select(.labels | map(.name) | index("status:deferred")) | .number',
15327
+ ` ' | tr '\\n' ' ')"`,
15328
+ "",
15262
15329
  " local issue_data",
15263
15330
  ` issue_data=$(echo "$issues" | jq -r '`,
15264
15331
  " .[] |",
@@ -15271,10 +15338,20 @@ function buildCheckBlockedScript(tiers, scopeGate, _runRatio) {
15271
15338
  " # mirroring unblock-dependents.sh.",
15272
15339
  " local unblocked_count=0",
15273
15340
  " local still_blocked_count=0",
15341
+ " local deferred_skipped_count=0",
15274
15342
  "",
15275
15343
  " while IFS=$'\\t' read -r num dep_line; do",
15276
15344
  ' [[ -z "$num" ]] && continue',
15277
15345
  "",
15346
+ " # Deliberately-parked issues never get promoted by a sweep, even",
15347
+ " # when every dependency has closed. Only a human clears",
15348
+ " # `status:deferred`.",
15349
+ ' if [[ "$deferred_set" == *" ${num} "* ]]; then',
15350
+ ' echo "SKIP_DEFERRED #${num} \u2014 status:deferred; human-parked, not promoting"',
15351
+ " deferred_skipped_count=$((deferred_skipped_count + 1))",
15352
+ " continue",
15353
+ " fi",
15354
+ "",
15278
15355
  ' if [[ -z "$dep_line" ]]; then',
15279
15356
  ' echo "BLOCKED #${num} \u2014 no Depends on field found"',
15280
15357
  " still_blocked_count=$((still_blocked_count + 1))",
@@ -15335,7 +15412,7 @@ function buildCheckBlockedScript(tiers, scopeGate, _runRatio) {
15335
15412
  ' done <<< "$issue_data"',
15336
15413
  "",
15337
15414
  " # Single summary line consumed by the orchestrator.",
15338
- ' echo "TRIAGE_DONE unblocked=${unblocked_count} still_blocked=${still_blocked_count}"',
15415
+ ' echo "TRIAGE_DONE unblocked=${unblocked_count} still_blocked=${still_blocked_count} deferred_skipped=${deferred_skipped_count}"',
15339
15416
  "}",
15340
15417
  "",
15341
15418
  "cmd_eligible() {",
@@ -15359,11 +15436,26 @@ function buildCheckBlockedScript(tiers, scopeGate, _runRatio) {
15359
15436
  " continue",
15360
15437
  " fi",
15361
15438
  "",
15439
+ " # Dispatch exclusions. `gh issue list` has no negative-label filter",
15440
+ " # for a label-filtered (non-search) listing, so both exclusions run",
15441
+ " # jq-side over the labels already fetched above \u2014 no new TSV field",
15442
+ " # is needed, and the mandatory-last dep_line ordering is untouched.",
15443
+ " # - `status:needs-attention` is additive (it no longer replaces the",
15444
+ " # base status), so a scope-gate-flagged issue keeps `status:ready`",
15445
+ " # and would re-surface in every scan until a human clears the flag",
15446
+ " # (#901). It is never dispatchable, so drop it from the scan.",
15447
+ " # - `status:deferred` is human-parked: captured for provenance and",
15448
+ " # never auto-dispatched. `status:ready` + `status:deferred` is",
15449
+ " # reachable (e.g. after an unblock or a manual edit), so exclude",
15450
+ " # it here as the dispatch-side half of the #887 guard.",
15362
15451
  " local issue_data",
15363
15452
  ` issue_data=$(echo "$issues" | jq -r '`,
15364
15453
  " .[] |",
15454
+ " (.labels | map(.name)) as $names |",
15455
+ ' select($names | index("status:needs-attention") | not) |',
15456
+ ' select($names | index("status:deferred") | not) |',
15365
15457
  ' (.body | split("\\n") | map(select(test("Depends on:"; "i"))) | join(" ")) as $dep_line |',
15366
- ' (.labels | map(.name) | map(select(startswith("type:"))) | .[0] // "") as $type_label |',
15458
+ ' ($names | map(select(startswith("type:"))) | .[0] // "") as $type_label |',
15367
15459
  ' "\\(.number)\\t\\(.title)\\t\\($type_label)\\t\\($dep_line)"',
15368
15460
  " ')",
15369
15461
  "",
@@ -16007,7 +16099,7 @@ function buildCheckBlockedScript(tiers, scopeGate, _runRatio) {
16007
16099
  function buildCheckBlockedProcedure(tiers, scopeGate = resolveScopeGate(), runRatio = resolveRunRatio()) {
16008
16100
  return {
16009
16101
  name: "check-blocked.sh",
16010
- description: "Token-efficient issue triage script with subcommands: eligible, unblock, stale, orphaned, lease-reconcile, maintenance, prs, scope. Sorts eligible issues by priority desc \u2192 funnel tier asc \u2192 issue number asc; the scope subcommand classifies a single issue against the scope-gate thresholds; the unblock subcommand applies the `status:blocked` \u2192 `status:ready` label flip itself, posts the canned unblock comment, and emits a single `TRIAGE_DONE unblocked=N still_blocked=M` summary line; the lease-reconcile subcommand auto-reconciles stuck `review:fixing` PR leases \u2014 re-applying `review:needs-worker` on an orphaned lease (fix-list stale, no worker report) so the Phase B1 drain retries, and removing `review:needs-worker` on a consumed-but-uncleared wedge (branch HEAD advanced past the fix-list, marker still set, no worker report) so the reviewer confirm pass can merge, always posting an audit-trail note comment and emitting a single `LEASE_RECONCILE orphaned=N consumed_uncleared=M` summary line; the maintenance subcommand flags stale issues with `status:needs-attention` (never auto-resets to `status:ready`), counts orphan branches/PRs, folds in the lease-reconcile sweep, and emits a `MAINTENANCE_DONE flagged_stale=N flagged_blocked=M orphan_branches=A orphan_prs=B needs_attention_total=T` summary line followed by the `LEASE_RECONCILE` line.",
16102
+ description: "Token-efficient issue triage script with subcommands: eligible, unblock, stale, orphaned, lease-reconcile, maintenance, prs, scope. Sorts eligible issues by priority desc \u2192 funnel tier asc \u2192 issue number asc, excluding issues carrying `status:needs-attention` or `status:deferred`; the scope subcommand classifies a single issue against the scope-gate thresholds; the unblock subcommand applies the `status:blocked` \u2192 `status:ready` label flip itself, posts the canned unblock comment, skips human-parked `status:deferred` candidates with a `SKIP_DEFERRED` line, and emits a single `TRIAGE_DONE unblocked=N still_blocked=M deferred_skipped=K` summary line; the lease-reconcile subcommand auto-reconciles stuck `review:fixing` PR leases \u2014 re-applying `review:needs-worker` on an orphaned lease (fix-list stale, no worker report) so the Phase B1 drain retries, and removing `review:needs-worker` on a consumed-but-uncleared wedge (branch HEAD advanced past the fix-list, marker still set, no worker report) so the reviewer confirm pass can merge, always posting an audit-trail note comment and emitting a single `LEASE_RECONCILE orphaned=N consumed_uncleared=M` summary line; the maintenance subcommand flags stale issues with `status:needs-attention` (never auto-resets to `status:ready`), counts orphan branches/PRs, folds in the lease-reconcile sweep, and emits a `MAINTENANCE_DONE flagged_stale=N flagged_blocked=M orphan_branches=A orphan_prs=B needs_attention_total=T` summary line followed by the `LEASE_RECONCILE` line.",
16011
16103
  content: buildCheckBlockedScript(tiers, scopeGate, runRatio)
16012
16104
  };
16013
16105
  }
@@ -16689,14 +16781,20 @@ var orchestratorSubAgent = {
16689
16781
  "The script emits one summary line in this shape:",
16690
16782
  "",
16691
16783
  "```",
16692
- "TRIAGE_DONE unblocked=<N> still_blocked=<M>",
16784
+ "TRIAGE_DONE unblocked=<N> still_blocked=<M> deferred_skipped=<K>",
16693
16785
  "```",
16694
16786
  "",
16695
16787
  "Per-issue informational lines (`UNBLOCKED #N`, `UNBLOCK_FAILED #N`,",
16696
- "`STILL_BLOCKED #N`, `BLOCKED #N \u2014 no Depends on field found`) are",
16697
- "emitted for log visibility but are **not** load-bearing for the",
16698
- "orchestrator \u2014 partial failures (one bad `gh` call) do not abort",
16699
- "the sweep, they are simply counted toward `still_blocked`.",
16788
+ "`STILL_BLOCKED #N`, `SKIP_DEFERRED #N`, `BLOCKED #N \u2014 no Depends on",
16789
+ "field found`) are emitted for log visibility but are **not**",
16790
+ "load-bearing for the orchestrator \u2014 partial failures (one bad `gh`",
16791
+ "call) do not abort the sweep, they are simply counted toward",
16792
+ "`still_blocked`.",
16793
+ "",
16794
+ "`deferred_skipped` counts candidates the sweep deliberately left",
16795
+ "blocked because they carry `status:deferred`. Those issues are",
16796
+ "human-parked: no agent or sweep ever removes `status:deferred`, so",
16797
+ "a non-zero count is expected steady-state noise, not a failure.",
16700
16798
  "",
16701
16799
  "This phase is the **fallback safety net** for agent-driven",
16702
16800
  "unblocking. Every agent that applies `status:done` already runs",
@@ -17876,9 +17974,11 @@ var checkBlockedCommand = {
17876
17974
  "reference, applies the `status:blocked` \u2192 `status:ready` label flip",
17877
17975
  "itself, posts the canned `Dependencies resolved \u2014 unblocking.`",
17878
17976
  "comment, and emits a single",
17879
- "`TRIAGE_DONE unblocked=<N> still_blocked=<M>` summary line. Per-issue",
17880
- "informational lines (`UNBLOCKED`, `UNBLOCK_FAILED`, `STILL_BLOCKED`)",
17881
- "are also emitted for log visibility.",
17977
+ "`TRIAGE_DONE unblocked=<N> still_blocked=<M> deferred_skipped=<K>`",
17978
+ "summary line. Candidates carrying `status:deferred` are skipped",
17979
+ "rather than promoted \u2014 only a human clears that label. Per-issue",
17980
+ "informational lines (`UNBLOCKED`, `UNBLOCK_FAILED`, `STILL_BLOCKED`,",
17981
+ "`SKIP_DEFERRED`) are also emitted for log visibility.",
17882
17982
  "",
17883
17983
  "Summarise the output (the `TRIAGE_DONE` counts and the first few",
17884
17984
  "per-issue lines) \u2014 do **not** apply additional label flips yourself;",