You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* fix(triage): exonerate the reducer for the stuck-Send + clear input on Start-over (PP-4846)
PP-4846 (repro-first): after Discard → pick a different category → type, the Send
arrow intermittently stayed disabled. It did not reproduce deterministically.
Pinned the REDUCER side of that flow — the source of truth the Send button's
`disabled` predicate reads (`!isFollowUpStep && inputText.trimmed.isEmpty`).
`StuckSendReproTests` drives Discard → re-category → type and proves inputText is
set and the step is a composition step, i.e. Send is enabled at the reducer
level. So the intermittent field report is localized to the SwiftUI TextField
binding (consistent with the "UIKit gesture-timeout" log + the non-determinism),
NOT the state machine.
Writing that test surfaced a real, separate latent bug: `.userTappedStartOver`
returned to `.awaitingCategory` but did NOT clear `inputText`, so a half-typed
composer survived "start fresh" — unlike Discard, which lands empty. In practice
Start-over is reached with inputText already empty (post-submit), but the two
reset paths should have identical composer semantics. Now both clear it.
Verified: TriageBotCore reducer suites green (StuckSendReproTests +
CategoryChipDebounce + StructuredEscalation, 13/13).
**Scope:** the Start-over reset clears inputText; reducer-level tests for both
reset paths. No SwiftUI change.
**Not done:** the intermittent SwiftUI TextField(axis:.vertical) binding
re-sync itself — reducer is exonerated; recommended fix is the local-@State
mirror pattern already used by TicketPreviewCard, but it can't be verified
without a deterministic repro, so it is not shipped blind here.
**Deferred:** a simdrive repro harness for the SwiftUI race (needs a dedicated
run; the field bug is intermittent).
* feat(reporting): world-class PR report contract + decision-first automated comments
Root cause: The PR record had an inverted signal budget. The authored layer
(bodies + commit messages) was world-class, but the automated layer buried it —
a ~900-row all-green test table dwarfed the human body, the delta engine that
computes what-changed was silent, the ledger comment printed constant numbers on
every PR, and a disabled QAAtlas integration shipped a standing "set
OPENAI_API_KEY" banner. For an agent-authored / human-orchestrated codebase, the
load-bearing claims were also author-attested prose with no machine anchor.
Solution: Establish one PR Report Contract that every reporting surface serves,
and make the automated surfaces obey it.
- docs/architecture/pr-report-contract.md — the cohesion anchor: 4 goals
(orchestrator decision speed, grounded verifiability, durable forensic
reconstruction, fleet legibility) + 4 principles (decision-first,
delta-or-silent, grounded-verifiability, fleet-legible) + surface map + the
standing gap-question list.
- .github/PULL_REQUEST_TEMPLATE.md — the authored-layer contract (there was no
template): adds Evidence / Repro / Class / Obligations to Root-cause/Solution.
- docs/regressions/recurrence-classes.md — greppable Class taxonomy, seeded from
the classes agents already name in prose.
- unit-testing.yml — decision-first: full per-class matrix ALWAYS collapsed
(never dumped open); failures OPEN; deltas relabelled "what changed vs base"
with new-failures open; Skipped column + reconciliation icon so all-skipped
classes stop rendering as false-green 7|0|0; provenance footer.
- parse-xcresult.py — emit per-class `skipped` so the comment can reconcile rows.
- ledger.yml — delta-or-silent: drop the dead QAAtlas banner (qa domain is off),
name the layer violation instead of showing a bare count, and stop printing a
green "no dead code" over 0 analyzed files.
Evidence: py_compile (3 scripts) OK; YAML parse OK; actionlint clean on edited
regions (only pre-existing info-level shellcheck notes on untouched run: steps);
node --check on both github-script bodies OK; render-logic smoke test green for
6 cases incl. all-skipped→green, non-reconciling→warn, legacy 5-field tolerance.
The PR's own CI run is the machine anchor, dogfooding the contract.
**Scope:** dev-tooling + docs only. No Palace/ production code, no test-affecting
change. Comment-generator JS validated structurally (node --check) + render smoke
test; the live rendering is proven by this PR's own CI comments.
**Not done:** the .test-history develop cache-warm job (so deltas populate on PR
branches); freeze-red-before-overwrite in the sticky comment; a package-suite
(TriageBotCore) CI job to reproduce swift test counts; the cross-PR roll-up; the
~2 unmapped-status tests in parse-xcresult (the off-by-2) — the new ⚠️ row now
flags them but the parser normalization is not fixed here. All tracked as
Obligations on the PR.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(reporting): adopt ledger 0.9.7 (real monolith blast-radius) + ship componentRoots
Root cause: the Ledger engine treated the single Palace app target as one
file-less component, so app files were owned by nothing and blast-radius on
widely-imported packages (e.g. PalaceAuth on the sign-in path) falsely read
"nobody depends / Risk LOW" — the reason the ledger comment carried no trustworthy
signal on PRs.
Solution: adopt CodeAtlas Ledger 0.9.7 (SyncTek-LLC/ledger-dist), which indexes
Xcode app-target file membership, turns config componentRoots into real
file-owning components, and adds conservative symbol-reference edges. Ship the 32
validated componentRoots so the model decomposes Palace into its real modules
(Network, MyBooks, SignInLogic, …). Validated pre-merge: impact AuthCoordinator →
8 real dependents at CRITICAL; TPPNetworkExecutor resolves to Network; context
--focus MyBooks returns real files/symbols/deps.
**Scope:** ledger.yml version pin 0.9.6 -> 0.9.7 + tools/ledger/ledger-config.json
componentRoots. The install URL is unchanged (it redirects to SyncTek-LLC).
**Not done:** ledger job stays continue-on-error (advisory) for this dogfood
cycle before any consideration of blocking; the tool's own swift test has 12
pre-existing (non-regression) failures to clear first. accesslint artifact for
0.9.7 not added (matches 0.9.6; a11y behavior unchanged). impact display polish
(adjacent-folder/dup rows) deferred.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: t <t@t.io>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: .github/COMMIT_AND_PR_FOR_JIRA.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,11 @@
1
1
# Commit and PR format for JIRA
2
2
3
+
> This is the **authored layer** of the [PR Report Contract](../docs/architecture/pr-report-contract.md).
4
+
> The contract explains *why* the format exists (durable forensic record + fleet telemetry for an
5
+
> agent-authored, human-orchestrated codebase); this file is the concrete commit/PR format. The PR
6
+
> **body** is now driven by [`.github/PULL_REQUEST_TEMPLATE.md`](./PULL_REQUEST_TEMPLATE.md), which adds
7
+
> `Evidence` / `Repro` / `Class` / `Obligations` to the Root-cause/Solution/How-to-verify below.
8
+
3
9
When commits or PRs are linked to JIRA, the default post often shows only hash, author, date, one-line message, and file list. To make JIRA posts **useful** (root cause, what changed, how to verify), use the formats below.
0 commit comments