atris 3.30.1 → 3.30.3
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/AGENTS.md +6 -0
- package/atris/AGENTS.md +11 -0
- package/atris/CLAUDE.md +5 -0
- package/atris/atris.md +19 -4
- package/atris/policies/atris-design.md +71 -0
- package/atris/policies/design-seed.md +187 -0
- package/atris/skills/atris/SKILL.md +26 -3
- package/atris/skills/design/SKILL.md +3 -2
- package/atris/skills/loop/SKILL.md +5 -3
- package/atris/team/_template/MEMBER.md +19 -0
- package/atris.md +63 -23
- package/ax +1434 -1698
- package/bin/atris.js +5 -1
- package/commands/agent-spawn.js +2 -2
- package/commands/brain.js +92 -7
- package/commands/brainstorm.js +62 -22
- package/commands/business-sync.js +92 -8
- package/commands/business.js +13 -7
- package/commands/chat-scan.js +102 -0
- package/commands/computer.js +758 -15
- package/commands/deck.js +505 -105
- package/commands/init.js +6 -1
- package/commands/launchpad.js +638 -0
- package/commands/log-sync.js +44 -13
- package/commands/loop-front.js +290 -0
- package/commands/member.js +124 -3
- package/commands/mission.js +717 -32
- package/commands/pull.js +37 -28
- package/commands/pulse.js +11 -8
- package/commands/run.js +79 -39
- package/commands/sync.js +36 -17
- package/commands/task.js +342 -66
- package/commands/xp.js +3 -0
- package/commands/youtube.js +221 -7
- package/decks/README.md +89 -0
- package/decks/archetype-catalog.json +180 -0
- package/decks/atris-antislop-pitch.json +48 -0
- package/decks/atris-archetypes-v2.json +83 -0
- package/decks/atris-one-loop-pitch.json +80 -0
- package/decks/atris-seed-pitch-v3.json +118 -0
- package/decks/atris-seed-pitch-v4-skeleton.json +106 -0
- package/decks/atris-seed-pitch-v5.json +109 -0
- package/decks/atris-seed-pitch-v6.json +137 -0
- package/decks/atris-seed-pitch-v7.json +133 -0
- package/decks/atris-single-shot-proof.json +74 -0
- package/decks/mark-pincus-narrative.json +102 -0
- package/decks/mark-pincus-sourcery.json +94 -0
- package/decks/yash-applied-compute-detailed.json +150 -0
- package/decks/yash-applied-compute-generalist.json +82 -0
- package/decks/yash-applied-compute-narrative.json +54 -0
- package/lib/ax-prefs.js +5 -12
- package/lib/chat-log-scan.js +377 -0
- package/lib/context-gatherer.js +35 -1
- package/lib/deck-compose.js +145 -0
- package/lib/deck-history.js +64 -0
- package/lib/deck-layout.js +169 -0
- package/lib/deck-review.js +431 -0
- package/lib/deck-schema.js +154 -0
- package/lib/file-ops.js +2 -2
- package/lib/functional-owner.js +189 -0
- package/lib/slides-deck.js +512 -58
- package/lib/task-db.js +109 -2
- package/package.json +2 -1
- package/templates/business-starter/team/START_HERE.md +12 -8
- package/utils/auth.js +4 -0
- package/utils/config.js +4 -0
- package/atris/atrisDev.md +0 -717
package/commands/task.js
CHANGED
|
@@ -11,6 +11,10 @@ const { taskProofState, buildVerifiedProof } = require('../lib/task-proof');
|
|
|
11
11
|
const { evaluateAutoAccept, parseVerifyCommand } = require('../lib/auto-accept-certified');
|
|
12
12
|
const { extractReceiptEvidence } = require('../lib/receipt-evidence');
|
|
13
13
|
const escapeRegExp = require('../lib/escape-regexp');
|
|
14
|
+
const {
|
|
15
|
+
normalizeOwnerSlug,
|
|
16
|
+
resolveFunctionalOwner: resolveFunctionalTaskOwner,
|
|
17
|
+
} = require('../lib/functional-owner');
|
|
14
18
|
|
|
15
19
|
const DEFAULT_OWNER = process.env.ATRIS_AGENT_ID
|
|
16
20
|
|| process.env.USER
|
|
@@ -102,6 +106,8 @@ atris task - durable local task state (SQLite, gitignored)
|
|
|
102
106
|
Show the plain Plan before work starts
|
|
103
107
|
atris task ready <id> --proof "..." [--changed "..." --checked "..." --saved "..." --try "..."]
|
|
104
108
|
Agent proof ready; records Result if needed
|
|
109
|
+
atris task ready <id> --proof "..." [--happened "..." --checked "..." --tested "..." --decision "..."]
|
|
110
|
+
Agent proof ready; writes the human result receipt
|
|
105
111
|
atris task result <id> --changed "..." --checked "..." [--saved "..."] [--try "..."]
|
|
106
112
|
Show the plain Result and store trace on the task
|
|
107
113
|
atris task review-chat <id> [--as <owner>] Start a task-owned /codex verification chat
|
|
@@ -112,7 +118,7 @@ atris task - durable local task state (SQLite, gitignored)
|
|
|
112
118
|
atris task revise <id> --note "..." Send reviewed work back to Do
|
|
113
119
|
|
|
114
120
|
atris task add "<title>" [--tag <tag>] [--goal-id <id>] Create a task
|
|
115
|
-
atris task delegate "<title>" --to <
|
|
121
|
+
atris task delegate "<title>" [--to <member>] [--executed-by <engine>] [--goal-id <id>] Create assigned work
|
|
116
122
|
atris task plan <id> --goal "..." --exit "..." --proof-needed "..."
|
|
117
123
|
Record a task-owned Plan stage
|
|
118
124
|
atris task do <id> --as <owner> --first-move "..."
|
|
@@ -145,7 +151,7 @@ atris task - durable local task state (SQLite, gitignored)
|
|
|
145
151
|
atris task review <id> --reward <n> [--verify "<cmd>"]
|
|
146
152
|
Write review event + RSI episode
|
|
147
153
|
atris task reviews [--limit <n>] Show certified Review items for human accept/revise
|
|
148
|
-
atris task reviews --group-by <tag|owner|source> Cluster
|
|
154
|
+
atris task reviews --group-by <tag|owner|source> Cluster ready-to-land work for fast triage
|
|
149
155
|
atris task accept-group <key>=<value> --spot-check K --confirm-human-accept --as <you> --verified <ids>
|
|
150
156
|
Accept a whole cluster; career XP only on the K you verified
|
|
151
157
|
atris task status [--json] [--history] Compact live status for web/Swarlo
|
|
@@ -309,6 +315,15 @@ function textFlag(args, names) {
|
|
|
309
315
|
return '';
|
|
310
316
|
}
|
|
311
317
|
|
|
318
|
+
function landingFlags(args) {
|
|
319
|
+
return {
|
|
320
|
+
happened: textFlag(args, ['--happened', '--what-happened']),
|
|
321
|
+
checked: textFlag(args, ['--checked', '--how-checked']),
|
|
322
|
+
tested: textFlag(args, ['--tested', '--what-tested']),
|
|
323
|
+
decision: textFlag(args, ['--decision', '--acceptance']),
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
312
327
|
function numericFlag(args, name) {
|
|
313
328
|
const value = flag(args, name);
|
|
314
329
|
if (value === null || value === true || value === undefined) return null;
|
|
@@ -645,6 +660,10 @@ function reviewSummary(task, payload = {}) {
|
|
|
645
660
|
|
|
646
661
|
const title = String(task.title || 'this task').replace(/\s+/g, ' ').trim();
|
|
647
662
|
const plainTitle = title ? title.charAt(0).toLowerCase() + title.slice(1) : 'this task';
|
|
663
|
+
const approvalStatus = payload.approval_status || metadata.approval_status || null;
|
|
664
|
+
if (approvalStatus === 'revise') {
|
|
665
|
+
return `Rework requested for ${plainTitle}.`;
|
|
666
|
+
}
|
|
648
667
|
const careerText = [
|
|
649
668
|
task.tag,
|
|
650
669
|
metadata.goal_id,
|
|
@@ -659,20 +678,148 @@ function reviewSummary(task, payload = {}) {
|
|
|
659
678
|
|| careerText.includes('agent xp')
|
|
660
679
|
) {
|
|
661
680
|
if (task.status === 'done') {
|
|
662
|
-
return `
|
|
681
|
+
return `Landed AgentXP result for ${plainTitle}.`;
|
|
663
682
|
}
|
|
664
683
|
if (task.status === 'review') {
|
|
665
|
-
return
|
|
684
|
+
return `${plainTitle} is ready to land; land only if the proof is real.`;
|
|
666
685
|
}
|
|
667
|
-
return `This explains what
|
|
686
|
+
return `This explains what landing ${plainTitle} would make real for AgentXP.`;
|
|
668
687
|
}
|
|
669
688
|
if (task.status === 'done') {
|
|
670
|
-
return `
|
|
689
|
+
return `Landed result for ${plainTitle}.`;
|
|
671
690
|
}
|
|
672
691
|
if (task.status === 'review') {
|
|
673
|
-
return
|
|
674
|
-
}
|
|
675
|
-
return `This explains what
|
|
692
|
+
return `${plainTitle} is ready to land; land it or send it back.`;
|
|
693
|
+
}
|
|
694
|
+
return `This explains what landing ${plainTitle} would make real.`;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function titleToResultText(title) {
|
|
698
|
+
const text = String(title || 'this task').replace(/\s+/g, ' ').trim();
|
|
699
|
+
if (!text) return 'This task is ready to review.';
|
|
700
|
+
const [first, ...restParts] = text.split(' ');
|
|
701
|
+
const rest = restParts.join(' ');
|
|
702
|
+
const past = {
|
|
703
|
+
add: 'Added',
|
|
704
|
+
approve: 'Prepared approval for',
|
|
705
|
+
build: 'Built',
|
|
706
|
+
clean: 'Cleaned',
|
|
707
|
+
create: 'Created',
|
|
708
|
+
design: 'Designed',
|
|
709
|
+
document: 'Documented',
|
|
710
|
+
fix: 'Fixed',
|
|
711
|
+
make: 'Made',
|
|
712
|
+
replace: 'Replaced',
|
|
713
|
+
route: 'Routed',
|
|
714
|
+
run: 'Ran',
|
|
715
|
+
ship: 'Shipped',
|
|
716
|
+
update: 'Updated',
|
|
717
|
+
validate: 'Validated',
|
|
718
|
+
wire: 'Wired',
|
|
719
|
+
}[String(first || '').toLowerCase()];
|
|
720
|
+
if (past && rest) return `${past} ${rest}.`;
|
|
721
|
+
return `${text} is ready to review.`;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
function titleToReasonText(task, proof = '') {
|
|
725
|
+
const title = String(task?.title || '').replace(/\s+/g, ' ').trim();
|
|
726
|
+
const text = `${title} ${proof || ''}`.toLowerCase();
|
|
727
|
+
if (/\b(priv(?:ate|acy)|secret|payload|leak|redact)\b/.test(text)) {
|
|
728
|
+
return 'It keeps private data out of the fast human decision screen.';
|
|
729
|
+
}
|
|
730
|
+
if (/\bapprove\b/.test(text) && /\b(command|exact|preview|ux)\b/.test(text)) {
|
|
731
|
+
return 'It lets the operator see the next command without hunting.';
|
|
732
|
+
}
|
|
733
|
+
if (/\b(stale|expire|expired)\b/.test(text) && /\bapproval/.test(text)) {
|
|
734
|
+
return 'It stops old approvals from running after their context has gone stale.';
|
|
735
|
+
}
|
|
736
|
+
if (/\bapproval|approve|permission\b/.test(text)) {
|
|
737
|
+
return 'It keeps real-world side effects behind a clear human decision.';
|
|
738
|
+
}
|
|
739
|
+
if (/\btest|self-test|harness|verifier|proof\b/.test(text)) {
|
|
740
|
+
return 'It makes the check repeatable before the work lands.';
|
|
741
|
+
}
|
|
742
|
+
return 'It closes the user-visible gap named by the task.';
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
function proofToHumanCheck(proof) {
|
|
746
|
+
const text = String(proof || '').replace(/\s+/g, ' ').trim();
|
|
747
|
+
if (!text) return 'Proof is attached below.';
|
|
748
|
+
const lower = text.toLowerCase();
|
|
749
|
+
if (/\b(?:atris\s+)?task\s+(?:show|page)\b/.test(lower) && /\b(?:print|prints|printed|render|renders|rendered|show|shows|showed)\b/.test(lower)) {
|
|
750
|
+
return 'I opened the real task screen and checked the receipt renders before raw proof.';
|
|
751
|
+
}
|
|
752
|
+
if (/git\s+diff\s+--check/.test(lower) && /\bpass(?:ed)?\b/.test(lower)) {
|
|
753
|
+
if (/node\s+--test/.test(lower)) return 'I ran the behavior check and the diff cleanliness check.';
|
|
754
|
+
return 'I ran the diff cleanliness check.';
|
|
755
|
+
}
|
|
756
|
+
if (/\btypecheck\b/.test(lower) && /\bpass(?:ed)?\b/.test(lower)) return 'I ran the typecheck.';
|
|
757
|
+
if (/\bbuild\b/.test(lower) && /\bpass(?:ed)?\b/.test(lower)) return 'I ran the build check.';
|
|
758
|
+
if (/\btest\b/.test(lower) && /\bpass(?:ed)?\b/.test(lower)) return 'I ran the verifier named in the proof.';
|
|
759
|
+
if (/\bvalidat(?:e|ion|ed)\b/.test(lower) && /\bpass(?:ed)?\b/.test(lower)) return 'I ran the validation check.';
|
|
760
|
+
if (/\breview(?:ed)?\b/.test(lower)) return 'Review proof is attached below.';
|
|
761
|
+
return 'Proof is attached below.';
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
function taskReviewLandingTested(proof) {
|
|
765
|
+
const commands = taskReviewEvidenceCommands(proof, 3);
|
|
766
|
+
if (commands.length) return `I ran: ${commands.join(' | ')}.`;
|
|
767
|
+
const paths = taskReviewEvidencePaths(proof, 3);
|
|
768
|
+
if (paths.length) return `I inspected: ${paths.join(', ')}.`;
|
|
769
|
+
return String(proof || '').trim() ? 'I attached the proof below.' : 'No verifier command recorded yet.';
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
function landingPayloadValue(payload, metadata, key) {
|
|
773
|
+
const landing = payload && payload.landing && typeof payload.landing === 'object' ? payload.landing : {};
|
|
774
|
+
return landing[key]
|
|
775
|
+
|| payload && payload[`landing_${key}`]
|
|
776
|
+
|| metadata[`landing_${key}`]
|
|
777
|
+
|| null;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
function taskReviewLanding(task, review = {}, payload = {}) {
|
|
781
|
+
const metadata = task.metadata || {};
|
|
782
|
+
const proof = review.proof || payload.proof || metadata.latest_agent_proof || '';
|
|
783
|
+
const agentCertified = review.agent_certified === true || metadata.agent_certified === true;
|
|
784
|
+
const approvalStatus = review.approval_status || metadata.approval_status || null;
|
|
785
|
+
const explicitHappened = landingPayloadValue(payload, metadata, 'happened')
|
|
786
|
+
|| payload.changed || metadata.result_changed || metadata.human_changed || metadata.changed;
|
|
787
|
+
const explicitChecked = landingPayloadValue(payload, metadata, 'checked')
|
|
788
|
+
|| payload.checked || metadata.result_checked || metadata.human_checked || metadata.checked;
|
|
789
|
+
const explicitTested = landingPayloadValue(payload, metadata, 'tested');
|
|
790
|
+
const explicitDecision = landingPayloadValue(payload, metadata, 'decision');
|
|
791
|
+
const explicitReason = landingPayloadValue(payload, metadata, 'reason')
|
|
792
|
+
|| landingPayloadValue(payload, metadata, 'why')
|
|
793
|
+
|| payload.reason || payload.why || metadata.result_reason || metadata.review_reason || metadata.why_it_matters;
|
|
794
|
+
return {
|
|
795
|
+
happened: clipStatusText(explicitHappened || titleToResultText(task.title), 220),
|
|
796
|
+
reason: clipStatusText(explicitReason || titleToReasonText(task, proof), 220),
|
|
797
|
+
checked: clipStatusText(explicitChecked || proofToHumanCheck(proof), 220),
|
|
798
|
+
tested: clipStatusText(explicitTested || taskReviewLandingTested(proof), 260),
|
|
799
|
+
decision: clipStatusText(explicitDecision || (task.status === 'done'
|
|
800
|
+
? 'Landed. No action needed unless this regresses.'
|
|
801
|
+
: approvalStatus === 'revise'
|
|
802
|
+
? 'Rework requested. Fix the note, then send a new receipt.'
|
|
803
|
+
: approvalStatus === 'pending' && !agentCertified
|
|
804
|
+
? 'Needs one more check before landing; send it back if the receipt misses the point.'
|
|
805
|
+
: 'Land it if this matches the request; send it back if not.'), 220),
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
function taskReviewResult(task, review = {}, payload = {}) {
|
|
810
|
+
const metadata = task.metadata || {};
|
|
811
|
+
const ref = taskRef(task);
|
|
812
|
+
const landing = taskReviewLanding(task, review, payload);
|
|
813
|
+
const explicitSaved = payload.saved || metadata.result_saved || metadata.human_saved || metadata.saved;
|
|
814
|
+
return {
|
|
815
|
+
changed: landing.happened,
|
|
816
|
+
reason: landing.reason,
|
|
817
|
+
checked: landing.checked,
|
|
818
|
+
saved: clipStatusText(explicitSaved || (task.status === 'done'
|
|
819
|
+
? `Landed as ${ref}.`
|
|
820
|
+
: `Ready to land as ${ref}.`), 180),
|
|
821
|
+
accept: landing.decision,
|
|
822
|
+
};
|
|
676
823
|
}
|
|
677
824
|
|
|
678
825
|
function taskReviewSummary(task) {
|
|
@@ -681,7 +828,7 @@ function taskReviewSummary(task) {
|
|
|
681
828
|
const metadata = task.metadata || {};
|
|
682
829
|
if (!reviewed && !metadata.approval_status && !metadata.agent_review_pass_count && !metadata.human_revision_count && !metadata.agent_certified) return null;
|
|
683
830
|
if (reviewed && reviewed.event_type === 'revision_requested') {
|
|
684
|
-
|
|
831
|
+
const review = {
|
|
685
832
|
summary: reviewSummary(task, payload),
|
|
686
833
|
reward: null,
|
|
687
834
|
proof: null,
|
|
@@ -693,7 +840,10 @@ function taskReviewSummary(task) {
|
|
|
693
840
|
agent_certification_policy: null,
|
|
694
841
|
human_revision_count: metadata.human_revision_count || payload.revision_count || null,
|
|
695
842
|
human_revision_note: metadata.human_revision_note || payload.note || null,
|
|
696
|
-
}
|
|
843
|
+
};
|
|
844
|
+
review.landing = taskReviewLanding(task, review, payload);
|
|
845
|
+
review.result = taskReviewResult(task, review, payload);
|
|
846
|
+
return reviewSummaryWithVerificationChat(task, review);
|
|
697
847
|
}
|
|
698
848
|
const reviewPassCount = Number(metadata.agent_review_pass_count || payload.review_pass_count || 0);
|
|
699
849
|
const agentCertified = metadata.agent_certified === true
|
|
@@ -713,7 +863,7 @@ function taskReviewSummary(task) {
|
|
|
713
863
|
}
|
|
714
864
|
return payload[key] || metadata[metadataKey] || null;
|
|
715
865
|
};
|
|
716
|
-
|
|
866
|
+
const review = {
|
|
717
867
|
summary: reviewSummary(task, payload),
|
|
718
868
|
reward: reviewed && reviewed.event_type === 'reviewed' && payload.reward !== undefined ? payload.reward : null,
|
|
719
869
|
proof: readyField('proof', 'latest_agent_proof'),
|
|
@@ -726,7 +876,10 @@ function taskReviewSummary(task) {
|
|
|
726
876
|
|| payload.agent_certification_policy
|
|
727
877
|
|| (agentCertified ? `${AGENT_CERTIFICATION_REVIEW_PASSES}_agent_review_passes` : null),
|
|
728
878
|
human_revision_count: metadata.human_revision_count || null,
|
|
729
|
-
}
|
|
879
|
+
};
|
|
880
|
+
review.landing = taskReviewLanding(task, review, payload);
|
|
881
|
+
review.result = taskReviewResult(task, review, payload);
|
|
882
|
+
return reviewSummaryWithVerificationChat(task, review);
|
|
730
883
|
}
|
|
731
884
|
|
|
732
885
|
function reviewSummaryWithVerificationChat(task, review) {
|
|
@@ -951,6 +1104,15 @@ function taskDescriptionForCloud(task) {
|
|
|
951
1104
|
lines.push(`- ${message.actor || 'unknown'}: ${message.content}`);
|
|
952
1105
|
}
|
|
953
1106
|
}
|
|
1107
|
+
const landing = reviewLandingForDisplay(task.review);
|
|
1108
|
+
if (landing) {
|
|
1109
|
+
lines.push('', 'Result:');
|
|
1110
|
+
if (landing.happened) lines.push(`What happened: ${landing.happened}`);
|
|
1111
|
+
if (landing.reason) lines.push(`Why it matters: ${landing.reason}`);
|
|
1112
|
+
if (landing.checked) lines.push(`How checked: ${landing.checked}`);
|
|
1113
|
+
if (landing.tested) lines.push(`Tested: ${landing.tested}`);
|
|
1114
|
+
if (landing.decision) lines.push(`Decision: ${landing.decision}`);
|
|
1115
|
+
}
|
|
954
1116
|
const reviewed = (task.events || []).slice().reverse().find(e => e.event_type === 'reviewed');
|
|
955
1117
|
if (reviewed && reviewed.payload) {
|
|
956
1118
|
if (reviewed.payload.proof) lines.push('', `Proof: ${reviewed.payload.proof}`);
|
|
@@ -964,6 +1126,32 @@ function taskDescriptionForCloud(task) {
|
|
|
964
1126
|
return lines.join('\n').slice(0, 5000);
|
|
965
1127
|
}
|
|
966
1128
|
|
|
1129
|
+
function reviewLandingForDisplay(review) {
|
|
1130
|
+
if (!review) return null;
|
|
1131
|
+
if (review.landing) return review.landing;
|
|
1132
|
+
if (!review.result) return null;
|
|
1133
|
+
return {
|
|
1134
|
+
happened: review.result.changed || null,
|
|
1135
|
+
reason: review.result.reason || null,
|
|
1136
|
+
checked: review.result.checked || null,
|
|
1137
|
+
tested: review.proof ? taskReviewLandingTested(review.proof) : null,
|
|
1138
|
+
decision: review.result.accept || null,
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
function printReviewLanding(review) {
|
|
1143
|
+
const landing = reviewLandingForDisplay(review);
|
|
1144
|
+
if (!landing) return false;
|
|
1145
|
+
console.log('Result:');
|
|
1146
|
+
if (landing.happened) console.log(` What happened: ${landing.happened}`);
|
|
1147
|
+
if (landing.reason) console.log(` Why it matters: ${landing.reason}`);
|
|
1148
|
+
if (landing.checked) console.log(` How I checked: ${landing.checked}`);
|
|
1149
|
+
if (landing.tested) console.log(` What I tested: ${landing.tested}`);
|
|
1150
|
+
if (review.result && review.result.saved) console.log(` Saved: ${review.result.saved}`);
|
|
1151
|
+
if (landing.decision) console.log(` Decision: ${landing.decision}`);
|
|
1152
|
+
return true;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
967
1155
|
function cloudPayloadForTask(task, businessId) {
|
|
968
1156
|
const metadata = task.metadata || {};
|
|
969
1157
|
const claimedAtEvent = (task.events || []).find(e => e.event_type === 'claimed');
|
|
@@ -1381,6 +1569,8 @@ function compactTaskForStatus(task) {
|
|
|
1381
1569
|
const review = {};
|
|
1382
1570
|
if (typeof task.review.reward === 'number') review.reward = task.review.reward;
|
|
1383
1571
|
else if (task.review.reward === null) review.reward = null;
|
|
1572
|
+
if (task.review.landing) review.landing = task.review.landing;
|
|
1573
|
+
if (task.review.result) review.result = task.review.result;
|
|
1384
1574
|
if (task.review.summary) review.summary = clipStatusText(task.review.summary, 240);
|
|
1385
1575
|
if (task.review.proof) review.proof = clipStatusText(task.review.proof, 180);
|
|
1386
1576
|
if (task.review.lesson) review.lesson = clipStatusText(task.review.lesson, 180);
|
|
@@ -1404,7 +1594,7 @@ function compactTaskForStatus(task) {
|
|
|
1404
1594
|
if (Object.keys(lineage).length) out.lineage = lineage;
|
|
1405
1595
|
}
|
|
1406
1596
|
const compactMetadata = {};
|
|
1407
|
-
for (const key of ['todo_id', 'stage', 'verify', 'delegate_via', 'goal_id', 'task_goal', 'goal_objective', 'approval_status', 'agent_review_pass_count', 'agent_certified', 'agent_certification_policy', 'human_revision_count', 'human_revision_note']) {
|
|
1597
|
+
for (const key of ['todo_id', 'stage', 'verify', 'delegate_via', 'owner_resolution', 'requested_owner', 'executed_by', 'proposed_member', 'proposed_member_command', 'goal_id', 'task_goal', 'goal_objective', 'approval_status', 'agent_review_pass_count', 'agent_certified', 'agent_certification_policy', 'human_revision_count', 'human_revision_note']) {
|
|
1408
1598
|
if (metadata[key]) compactMetadata[key] = key === 'verify' ? clipStatusText(metadata[key], 180) : metadata[key];
|
|
1409
1599
|
}
|
|
1410
1600
|
if (Object.keys(compactMetadata).length) out.metadata = compactMetadata;
|
|
@@ -1598,9 +1788,20 @@ function sortTasksNewestFirst(tasks) {
|
|
|
1598
1788
|
});
|
|
1599
1789
|
}
|
|
1600
1790
|
|
|
1791
|
+
function sortTasksOldestFirst(tasks) {
|
|
1792
|
+
return [...tasks].sort((a, b) => {
|
|
1793
|
+
const byUpdated = Number(a.updated_at || 0) - Number(b.updated_at || 0);
|
|
1794
|
+
if (byUpdated) return byUpdated;
|
|
1795
|
+
return String(a.title || '').localeCompare(String(b.title || ''));
|
|
1796
|
+
});
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1601
1799
|
function taskQueueItem(task, { reviewer = 'codex-review', hasExistingReviewFollowUp = null } = {}) {
|
|
1602
1800
|
const page = taskPageContract(task, { reviewer, hasExistingReviewFollowUp });
|
|
1603
1801
|
const item = compactTaskForStatus(task) || {};
|
|
1802
|
+
item.ref = taskRef(task);
|
|
1803
|
+
item.display_id = item.display_id || task.display_id || null;
|
|
1804
|
+
item.legacy_ref = item.legacy_ref || task.legacy_ref || taskRef(task.id);
|
|
1604
1805
|
if (item.review && item.review.verification_chat) {
|
|
1605
1806
|
item.review = { ...item.review };
|
|
1606
1807
|
delete item.review.verification_chat;
|
|
@@ -2682,7 +2883,8 @@ function taskQueueContract(projection, { reviewer = 'codex-review', limit = 8, s
|
|
|
2682
2883
|
}
|
|
2683
2884
|
|
|
2684
2885
|
function selectTaskForCurrent(projection, { owner = DEFAULT_OWNER, scope = {}, hasExistingReviewFollowUp = null } = {}) {
|
|
2685
|
-
const
|
|
2886
|
+
const normalizedScope = normalizeTaskQueueScope(scope);
|
|
2887
|
+
const tasks = filterTasksByScope(sortTasksNewestFirst(projection.tasks || []), normalizedScope, { hasExistingReviewFollowUp });
|
|
2686
2888
|
const columns = {
|
|
2687
2889
|
backlog: [],
|
|
2688
2890
|
plan: [],
|
|
@@ -2703,7 +2905,8 @@ function selectTaskForCurrent(projection, { owner = DEFAULT_OWNER, scope = {}, h
|
|
|
2703
2905
|
if (reviewNeedsAgent) return { task: reviewNeedsAgent, reason: 'review_needs_agent_verification' };
|
|
2704
2906
|
const reviewProofBoundaryBlocked = columns.review.find(task => reviewHandoffForTask(task, { suppressExistingFollowUp: true, hasExistingReviewFollowUp })?.next_action === PROOF_BOUNDARY_BLOCKED_ACTION);
|
|
2705
2907
|
if (reviewProofBoundaryBlocked) return { task: reviewProofBoundaryBlocked, reason: 'review_proof_boundary_blocked' };
|
|
2706
|
-
const
|
|
2908
|
+
const planQueue = normalizedScope.goal_id ? sortTasksOldestFirst(columns.plan) : columns.plan;
|
|
2909
|
+
const planReady = planQueue[0];
|
|
2707
2910
|
if (planReady) return { task: planReady, reason: 'plan_ready' };
|
|
2708
2911
|
const backlogIdea = columns.backlog[0];
|
|
2709
2912
|
if (backlogIdea) return { task: backlogIdea, reason: 'backlog_idea' };
|
|
@@ -3821,10 +4024,14 @@ function reviewQueueItem(task, root = process.cwd(), evidence = undefined) {
|
|
|
3821
4024
|
tag: task.tag || null,
|
|
3822
4025
|
updated_at: task.updated_at || null,
|
|
3823
4026
|
review_pass_count: task.review?.agent_review_pass_count || null,
|
|
4027
|
+
landing: reviewLandingForDisplay(task.review),
|
|
4028
|
+
result: task.review?.result || null,
|
|
3824
4029
|
proof: taskReviewClip(task.review?.proof, 500) || null,
|
|
3825
4030
|
next_action: handoff?.next_action || null,
|
|
3826
4031
|
accept_command: acceptCommand,
|
|
4032
|
+
land_command: acceptCommand,
|
|
3827
4033
|
revise_command: `atris task revise ${ref} --note "<what must change>"`,
|
|
4034
|
+
send_back_command: `atris task revise ${ref} --note "<what must change>"`,
|
|
3828
4035
|
};
|
|
3829
4036
|
const resolvedEvidence = evidence === undefined ? extractReceiptEvidence(task.review?.proof, root) : evidence;
|
|
3830
4037
|
if (resolvedEvidence) item.evidence = resolvedEvidence;
|
|
@@ -3968,13 +4175,13 @@ function cmdReviews(args) {
|
|
|
3968
4175
|
printJson({ ok: true, action: 'review_groups', projection_path: outPath, groups });
|
|
3969
4176
|
return;
|
|
3970
4177
|
}
|
|
3971
|
-
console.log(`
|
|
3972
|
-
console.log(`${groups.total_certified}
|
|
4178
|
+
console.log(`READY TO LAND — grouped by ${key}`);
|
|
4179
|
+
console.log(`${groups.total_certified} ready to land across ${groups.group_count} ${key} group(s)`);
|
|
3973
4180
|
groups.groups.forEach((g, index) => {
|
|
3974
4181
|
console.log('');
|
|
3975
4182
|
console.log(`${index + 1}. ${g.value} — ${g.count} task${g.count === 1 ? '' : 's'}`);
|
|
3976
4183
|
g.sample_titles.forEach(title => console.log(` • ${title}`));
|
|
3977
|
-
console.log(`
|
|
4184
|
+
console.log(` land this group: ${g.accept_group_command} --confirm-human-accept --as <you>`);
|
|
3978
4185
|
});
|
|
3979
4186
|
return;
|
|
3980
4187
|
}
|
|
@@ -3988,10 +4195,10 @@ function cmdReviews(args) {
|
|
|
3988
4195
|
});
|
|
3989
4196
|
return;
|
|
3990
4197
|
}
|
|
3991
|
-
console.log('
|
|
3992
|
-
console.log(`${queue.counts.certified}
|
|
4198
|
+
console.log('READY TO LAND');
|
|
4199
|
+
console.log(`${queue.counts.certified} ready to land / ${queue.counts.blocking} need one more check / ${queue.counts.review} total waiting`);
|
|
3993
4200
|
if (!queue.items.length) {
|
|
3994
|
-
console.log('
|
|
4201
|
+
console.log('Nothing is ready to land.');
|
|
3995
4202
|
return;
|
|
3996
4203
|
}
|
|
3997
4204
|
queue.items.forEach((item, index) => {
|
|
@@ -4000,7 +4207,16 @@ function cmdReviews(args) {
|
|
|
4000
4207
|
const badge = item.evidence?.all_passing ? ' [evidence:passing]' : '';
|
|
4001
4208
|
console.log('');
|
|
4002
4209
|
console.log(`${index + 1}. ${item.display_id || taskRef(item.id)}${tag}${passes}: ${item.title}${badge}`);
|
|
4003
|
-
if (item.
|
|
4210
|
+
if (item.landing) {
|
|
4211
|
+
console.log(' Result:');
|
|
4212
|
+
if (item.landing.happened) console.log(` What happened: ${item.landing.happened}`);
|
|
4213
|
+
if (item.landing.reason) console.log(` Why it matters: ${item.landing.reason}`);
|
|
4214
|
+
if (item.landing.checked) console.log(` How I checked: ${item.landing.checked}`);
|
|
4215
|
+
if (item.landing.tested) console.log(` What I tested: ${item.landing.tested}`);
|
|
4216
|
+
if (item.result?.saved) console.log(` Saved: ${item.result.saved}`);
|
|
4217
|
+
if (item.landing.decision) console.log(` Decision: ${item.landing.decision}`);
|
|
4218
|
+
}
|
|
4219
|
+
if (item.proof) console.log(` details: ${item.proof}`);
|
|
4004
4220
|
if (item.evidence) {
|
|
4005
4221
|
item.evidence.receipts.forEach((receipt) => {
|
|
4006
4222
|
const verdict = receipt.verifier_passed === true ? ' verifier:passed'
|
|
@@ -4011,9 +4227,9 @@ function cmdReviews(args) {
|
|
|
4011
4227
|
}
|
|
4012
4228
|
if (item.review_chat_command) console.log(` /codex: ${item.review_chat_command}`);
|
|
4013
4229
|
if (item.continue_work_command) console.log(` continue: ${item.continue_work_command}`);
|
|
4014
|
-
if (item.accept_command) console.log(`
|
|
4015
|
-
else if (item.blocked_accept_reason) console.log(`
|
|
4016
|
-
console.log(`
|
|
4230
|
+
if (item.accept_command) console.log(` land: ${item.accept_command}`);
|
|
4231
|
+
else if (item.blocked_accept_reason) console.log(` land: blocked (${item.blocked_accept_reason})`);
|
|
4232
|
+
console.log(` send back: ${item.revise_command}`);
|
|
4017
4233
|
});
|
|
4018
4234
|
if (queue.counts.shown < queue.counts.certified) {
|
|
4019
4235
|
console.log('');
|
|
@@ -4380,13 +4596,9 @@ function delegateHandoff(task, owner, via, tag) {
|
|
|
4380
4596
|
function cmdDelegate(args) {
|
|
4381
4597
|
const pos = positional(args);
|
|
4382
4598
|
const title = pos.join(' ').trim();
|
|
4383
|
-
const owner = flag(args, '--to') || flag(args, '--as');
|
|
4384
4599
|
if (!title) {
|
|
4385
4600
|
failTask('atris task delegate', 'missing_title', 'title required');
|
|
4386
4601
|
}
|
|
4387
|
-
if (!owner || owner === true) {
|
|
4388
|
-
failTask('atris task delegate', 'missing_owner', '--to <owner> required');
|
|
4389
|
-
}
|
|
4390
4602
|
const viaFlag = flag(args, '--via');
|
|
4391
4603
|
const via = viaFlag === 'swarlo' ? 'swarlo' : 'local';
|
|
4392
4604
|
const tag = flag(args, '--tag');
|
|
@@ -4394,15 +4606,36 @@ function cmdDelegate(args) {
|
|
|
4394
4606
|
const goalId = flag(args, '--goal-id');
|
|
4395
4607
|
const goalObjective = flag(args, '--goal-objective') || flag(args, '--goal');
|
|
4396
4608
|
const claimNow = hasFlag(args, '--claim');
|
|
4609
|
+
const requestedOwner = flag(args, '--to') || flag(args, '--as');
|
|
4610
|
+
const explicitExecutedBy = flag(args, '--executed-by');
|
|
4397
4611
|
const taskDb = getTaskDb();
|
|
4398
4612
|
const db = taskDb.open();
|
|
4399
4613
|
const ws = taskDb.workspaceRoot();
|
|
4614
|
+
const ownerResolution = resolveFunctionalTaskOwner({
|
|
4615
|
+
requestedOwner: requestedOwner && requestedOwner !== true ? requestedOwner : null,
|
|
4616
|
+
title,
|
|
4617
|
+
tag,
|
|
4618
|
+
note,
|
|
4619
|
+
goal: goalObjective && goalObjective !== true ? goalObjective : '',
|
|
4620
|
+
root: ws,
|
|
4621
|
+
});
|
|
4622
|
+
const owner = ownerResolution.owner;
|
|
4623
|
+
const executedBy = explicitExecutedBy && explicitExecutedBy !== true
|
|
4624
|
+
? normalizeOwnerSlug(explicitExecutedBy)
|
|
4625
|
+
: ownerResolution.executed_by;
|
|
4400
4626
|
const metadata = {
|
|
4401
|
-
assigned_to:
|
|
4627
|
+
assigned_to: owner,
|
|
4402
4628
|
delegate_via: via,
|
|
4403
4629
|
swarlo_channel: via === 'swarlo' ? String(tag || 'tasks') : null,
|
|
4404
4630
|
created_for_day: new Date().toISOString().slice(0, 10),
|
|
4631
|
+
owner_resolution: ownerResolution.reason,
|
|
4405
4632
|
};
|
|
4633
|
+
if (ownerResolution.requested_owner) metadata.requested_owner = ownerResolution.requested_owner;
|
|
4634
|
+
if (executedBy) metadata.executed_by = executedBy;
|
|
4635
|
+
if (ownerResolution.proposed_member) {
|
|
4636
|
+
metadata.proposed_member = ownerResolution.proposed_member;
|
|
4637
|
+
metadata.proposed_member_command = `atris member create ${ownerResolution.proposed_member} --role="${ownerResolution.proposed_member.replace(/-/g, ' ')}"`;
|
|
4638
|
+
}
|
|
4406
4639
|
if (goalId && goalId !== true) metadata.goal_id = String(goalId);
|
|
4407
4640
|
if (goalObjective && goalObjective !== true) {
|
|
4408
4641
|
metadata.task_goal = String(goalObjective);
|
|
@@ -4413,7 +4646,7 @@ function cmdDelegate(args) {
|
|
|
4413
4646
|
tag: typeof tag === 'string' ? tag : null,
|
|
4414
4647
|
workspaceRoot: ws,
|
|
4415
4648
|
status: claimNow ? 'claimed' : 'open',
|
|
4416
|
-
claimedBy: claimNow ?
|
|
4649
|
+
claimedBy: claimNow ? owner : null,
|
|
4417
4650
|
metadata,
|
|
4418
4651
|
});
|
|
4419
4652
|
if (typeof note === 'string' && note.trim()) {
|
|
@@ -4421,14 +4654,16 @@ function cmdDelegate(args) {
|
|
|
4421
4654
|
}
|
|
4422
4655
|
const { projection, outPath } = writeDefaultProjection(taskDb, db);
|
|
4423
4656
|
const task = compactTaskFromProjection(projection, result.id);
|
|
4424
|
-
const handoff = delegateHandoff(task,
|
|
4657
|
+
const handoff = delegateHandoff(task, owner, via, typeof tag === 'string' ? tag : null);
|
|
4425
4658
|
if (wantsJson(args)) {
|
|
4426
4659
|
printJson({
|
|
4427
4660
|
ok: true,
|
|
4428
4661
|
action: 'delegated',
|
|
4429
4662
|
task_id: result.id,
|
|
4430
4663
|
inserted: result.inserted !== false,
|
|
4431
|
-
owner
|
|
4664
|
+
owner,
|
|
4665
|
+
owner_resolution: ownerResolution,
|
|
4666
|
+
executed_by: executedBy || null,
|
|
4432
4667
|
via,
|
|
4433
4668
|
handoff,
|
|
4434
4669
|
projection_path: outPath,
|
|
@@ -4438,6 +4673,8 @@ function cmdDelegate(args) {
|
|
|
4438
4673
|
}
|
|
4439
4674
|
const tagText = tag && tag !== true ? ` #${tag}` : '';
|
|
4440
4675
|
console.log(`delegated ${taskRef(task)} -> ${owner}${tagText} via=${via}`);
|
|
4676
|
+
if (executedBy) console.log(`executed_by: ${executedBy}`);
|
|
4677
|
+
if (ownerResolution.proposed_member) console.log(`member: ${metadata.proposed_member_command}`);
|
|
4441
4678
|
console.log(`claim: ${handoff.command}`);
|
|
4442
4679
|
if (handoff.swarlo) console.log(`swarlo: ${handoff.swarlo.channel}/${handoff.swarlo.action}`);
|
|
4443
4680
|
}
|
|
@@ -4528,7 +4765,7 @@ function cmdDay(args) {
|
|
|
4528
4765
|
console.log(`stale ${staleFailed.length} failed >7d hidden — atris task list --status failed`);
|
|
4529
4766
|
}
|
|
4530
4767
|
console.log('');
|
|
4531
|
-
console.log('add: atris task delegate "..." --to
|
|
4768
|
+
console.log('add: atris task delegate "..." --to task-planner --tag tasks');
|
|
4532
4769
|
}
|
|
4533
4770
|
|
|
4534
4771
|
function cmdHome(args) {
|
|
@@ -4784,7 +5021,7 @@ function cmdNext(args) {
|
|
|
4784
5021
|
}
|
|
4785
5022
|
console.log(`created ${taskRef(createdTask)} @${owner}`);
|
|
4786
5023
|
console.log(createdTask.title);
|
|
4787
|
-
console.log(`Noted v${created.note_version}.
|
|
5024
|
+
console.log(`Noted v${created.note_version}. Landing remains pending on ${taskRef(reviewTask)}.`);
|
|
4788
5025
|
console.log(`Verify: ${nextAgentAction.task_seed.verifier}`);
|
|
4789
5026
|
return;
|
|
4790
5027
|
}
|
|
@@ -4805,12 +5042,12 @@ function cmdNext(args) {
|
|
|
4805
5042
|
}
|
|
4806
5043
|
console.log('No open tasks.');
|
|
4807
5044
|
console.log(handoff.next_action === 'agent_review_again'
|
|
4808
|
-
? `${taskRef(reviewTask)} needs one more agent
|
|
4809
|
-
: `${taskRef(reviewTask)} is
|
|
5045
|
+
? `${taskRef(reviewTask)} needs one more agent check before landing.`
|
|
5046
|
+
: `${taskRef(reviewTask)} is ready to land.`);
|
|
4810
5047
|
console.log(handoff.next_action === 'continue_work'
|
|
4811
|
-
? 'Continue work elsewhere;
|
|
5048
|
+
? 'Continue work elsewhere; XP lands after the human lands this task.'
|
|
4812
5049
|
: handoff.next_action === 'human_accept_waiting'
|
|
4813
|
-
? (nextAgentAction ? nextAgentAction.message : 'No
|
|
5050
|
+
? (nextAgentAction ? nextAgentAction.message : 'No next agent task is attached; this task is ready to land when the human decides.')
|
|
4814
5051
|
: 'Review this task again before continuing.');
|
|
4815
5052
|
if (nextAgentAction) console.log(`Command: ${nextAgentAction.command}`);
|
|
4816
5053
|
if (nextAgentAction && nextAgentAction.task_seed) {
|
|
@@ -5221,17 +5458,30 @@ function cmdShow(args) {
|
|
|
5221
5458
|
}
|
|
5222
5459
|
const owner = task.claimed_by ? ` / ${task.claimed_by}` : '';
|
|
5223
5460
|
const tag = task.tag ? ` #${task.tag}` : '';
|
|
5224
|
-
|
|
5461
|
+
const statusLabel = task.status === 'review'
|
|
5462
|
+
? 'READY TO LAND'
|
|
5463
|
+
: task.status === 'done'
|
|
5464
|
+
? 'LANDED'
|
|
5465
|
+
: task.status.toUpperCase();
|
|
5466
|
+
console.log(`${statusLabel} ${taskRef(task)} v${task.current_version}${owner}${tag}`);
|
|
5225
5467
|
console.log(task.title);
|
|
5226
5468
|
if (task.review) {
|
|
5227
5469
|
console.log('');
|
|
5228
|
-
|
|
5229
|
-
if (task.review.
|
|
5470
|
+
printReviewLanding(task.review);
|
|
5471
|
+
if (task.review.summary) console.log(`Short version: ${task.review.summary}`);
|
|
5472
|
+
if (task.review.proof) console.log(`Details: ${task.review.proof}`);
|
|
5230
5473
|
if (task.review.lesson) console.log(`Lesson: ${task.review.lesson}`);
|
|
5231
5474
|
if (task.review.next_task) console.log(`Next: ${task.review.next_task}`);
|
|
5232
|
-
if (task.review.approval_status)
|
|
5233
|
-
|
|
5234
|
-
|
|
5475
|
+
if (task.review.approval_status) {
|
|
5476
|
+
const landingStatus = task.review.approval_status === 'pending'
|
|
5477
|
+
? 'waiting on human'
|
|
5478
|
+
: task.review.approval_status === 'revise'
|
|
5479
|
+
? 'sent back'
|
|
5480
|
+
: task.review.approval_status;
|
|
5481
|
+
console.log(`Landing: ${landingStatus}`);
|
|
5482
|
+
}
|
|
5483
|
+
if (task.review.verification_chat) console.log(`Check command: ${task.review.verification_chat.command}`);
|
|
5484
|
+
if (task.review.agent_certified) console.log(`Checked: yes (${task.review.agent_review_pass_count || AGENT_CERTIFICATION_REVIEW_PASSES} agent checks)`);
|
|
5235
5485
|
}
|
|
5236
5486
|
if (task.messages.length) {
|
|
5237
5487
|
console.log('');
|
|
@@ -5273,10 +5523,11 @@ function cmdPage(args) {
|
|
|
5273
5523
|
console.log(`TASK PAGE ${taskRef(task)}`);
|
|
5274
5524
|
console.log(`Goal: ${page.goal.text || '(none)'}`);
|
|
5275
5525
|
console.log(`Stage: ${page.stage.current}`);
|
|
5526
|
+
printReviewLanding(page.review);
|
|
5276
5527
|
console.log(`Next: ${page.stage.next_action.command || page.stage.next_action.label}`);
|
|
5277
5528
|
console.log(`Chat: ${page.chat.command}`);
|
|
5278
|
-
if (page.review.verification_chat) console.log(`
|
|
5279
|
-
if (page.review.human_accept.enabled) console.log(`
|
|
5529
|
+
if (page.review.verification_chat) console.log(`Check command: ${page.review.verification_chat.command}`);
|
|
5530
|
+
if (page.review.human_accept.enabled) console.log(`Land: ${page.review.human_accept.command}`);
|
|
5280
5531
|
}
|
|
5281
5532
|
|
|
5282
5533
|
function cmdReviewChat(args) {
|
|
@@ -6013,7 +6264,7 @@ function taskPageActions(task, { reviewer = 'codex-review', hasExistingReviewFol
|
|
|
6013
6264
|
note_command: `atris task note ${ref} "<context>" --as ${owner}`,
|
|
6014
6265
|
plan_command: `atris task plan ${ref} --goal ${taskCommandQuote(goal)} --exit "<exit condition>" --proof-needed "<verification command>" --first-move "<first move>"`,
|
|
6015
6266
|
do_command: `atris task do ${ref} --as ${owner} --first-move "<first move>"`,
|
|
6016
|
-
ready_command: `atris task ready ${ref} --as ${owner} --proof "<specific proof command/result>"`,
|
|
6267
|
+
ready_command: `atris task ready ${ref} --as ${owner} --proof "<specific proof command/result>" --happened "<what happened>" --checked "<how you know>" --tested "<what you ran or inspected>" --decision "<accept/rework guidance>"`,
|
|
6017
6268
|
review_command: `atris task review ${ref} --reward 0 --as ${actor} --proof "<specific proof command/result>" --verify "<safe verifier command>"`,
|
|
6018
6269
|
};
|
|
6019
6270
|
if (task && task.status === 'review') {
|
|
@@ -6071,7 +6322,7 @@ function taskPageNextAction(task, current, actions, { hasExistingReviewFollowUp
|
|
|
6071
6322
|
if (handoff && handoff.next_action === 'human_accept_waiting') {
|
|
6072
6323
|
return {
|
|
6073
6324
|
key: 'human_accept_waiting',
|
|
6074
|
-
label: '
|
|
6325
|
+
label: 'Ready to land',
|
|
6075
6326
|
command: null,
|
|
6076
6327
|
api: null,
|
|
6077
6328
|
human_accept_command: actions.human_accept_command || null,
|
|
@@ -6092,6 +6343,7 @@ function taskPageContract(task, { reviewer = 'codex-review', hasExistingReviewFo
|
|
|
6092
6343
|
const metadata = task && task.metadata || {};
|
|
6093
6344
|
const current = taskPageCurrentStage(task);
|
|
6094
6345
|
const actions = taskPageActions(task, { reviewer, hasExistingReviewFollowUp });
|
|
6346
|
+
const review = task && (task.review || taskReviewSummary(task));
|
|
6095
6347
|
const recentMessages = (task && Array.isArray(task.messages) ? task.messages : []).slice(-10).map(message => ({
|
|
6096
6348
|
version: message.version || null,
|
|
6097
6349
|
actor: message.actor || null,
|
|
@@ -6135,9 +6387,13 @@ function taskPageContract(task, { reviewer = 'codex-review', hasExistingReviewFo
|
|
|
6135
6387
|
},
|
|
6136
6388
|
actions,
|
|
6137
6389
|
review: {
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6390
|
+
landing: review && review.landing || null,
|
|
6391
|
+
result: review && review.result || null,
|
|
6392
|
+
summary: review && review.summary || null,
|
|
6393
|
+
proof: review && review.proof || null,
|
|
6394
|
+
approval_status: review && review.approval_status || metadata.approval_status || null,
|
|
6395
|
+
agent_review_pass_count: review && review.agent_review_pass_count || metadata.agent_review_pass_count || null,
|
|
6396
|
+
agent_certified: Boolean(review && review.agent_certified || metadata.agent_certified),
|
|
6141
6397
|
verification_chat: reviewChat,
|
|
6142
6398
|
handoff: reviewHandoff,
|
|
6143
6399
|
human_accept: {
|
|
@@ -6188,7 +6444,7 @@ function appendTaskReviewChat(taskDb, db, taskId, { reviewer = 'codex-review', d
|
|
|
6188
6444
|
throw taskReviewChatError(`not_reviewable_${task.status}`, `review chat requires a task in Review; current status is ${task.status}`, { status: 409, exitCode: 1 });
|
|
6189
6445
|
}
|
|
6190
6446
|
if (!taskAllowsReviewChat(task, { allowCertified: true })) {
|
|
6191
|
-
throw taskReviewChatError('agent_certified_continue_work', 'review chat is closed after agent certification; continue other work or
|
|
6447
|
+
throw taskReviewChatError('agent_certified_continue_work', 'review chat is closed after agent certification; continue other work or land/send back this task', { status: 409, exitCode: 1 });
|
|
6192
6448
|
}
|
|
6193
6449
|
const contract = taskReviewChatContract(task, { reviewer: actor, allowCertified: true });
|
|
6194
6450
|
let event = null;
|
|
@@ -6345,8 +6601,8 @@ function readyHandoffForStep(task, proof, lesson, nextTask, agentCertified) {
|
|
|
6345
6601
|
career_xp_status: 'pending_human_accept',
|
|
6346
6602
|
next_action: agentCertified ? certifiedReviewNextAction(nextTask) : 'agent_review_again',
|
|
6347
6603
|
rule: agentCertified
|
|
6348
|
-
? '
|
|
6349
|
-
: 'Proof is
|
|
6604
|
+
? 'Double-check complete; ready to keep moving. XP lands only after the human lands the task.'
|
|
6605
|
+
: 'Proof is ready; one more agent check before landing. XP waits for the human.',
|
|
6350
6606
|
};
|
|
6351
6607
|
if (reviewChat) {
|
|
6352
6608
|
handoff.review_chat_command = reviewChat.command;
|
|
@@ -6367,7 +6623,7 @@ function runTaskStep(taskDb, db, taskId, options = {}) {
|
|
|
6367
6623
|
const reason = initialHandoffState.next_action === 'continue_work'
|
|
6368
6624
|
? 'agent_certified_continue_work'
|
|
6369
6625
|
: 'agent_certified_waiting_human';
|
|
6370
|
-
throw taskStepError(reason, 'atris task step:
|
|
6626
|
+
throw taskStepError(reason, 'atris task step: ready-to-land rows have no safe agent step; continue other work or land/send back this task', { status: 409, exitCode: 1, page: initialPage });
|
|
6371
6627
|
}
|
|
6372
6628
|
let chat = null;
|
|
6373
6629
|
const message = String(options.message || '').trim();
|
|
@@ -6469,7 +6725,7 @@ function runTaskStep(taskDb, db, taskId, options = {}) {
|
|
|
6469
6725
|
const reason = handoffState.next_action === 'continue_work'
|
|
6470
6726
|
? 'agent_certified_continue_work'
|
|
6471
6727
|
: 'agent_certified_waiting_human';
|
|
6472
|
-
throw taskStepError(reason, 'atris task step:
|
|
6728
|
+
throw taskStepError(reason, 'atris task step: ready-to-land rows have no safe agent step; continue other work or land/send back this task', { status: 409, exitCode: 1, page: actionPage });
|
|
6473
6729
|
}
|
|
6474
6730
|
const reviewed = appendTaskReviewChat(taskDb, db, taskId, { reviewer, dryRun: Boolean(options.dryRun) });
|
|
6475
6731
|
stepAction = 'review_chat';
|
|
@@ -6577,7 +6833,7 @@ function runCurrentTaskStep(taskDb, db, { owner = DEFAULT_OWNER, reviewer = 'cod
|
|
|
6577
6833
|
if (nextActionKey === 'human_accept_waiting') {
|
|
6578
6834
|
const error = taskStepError(
|
|
6579
6835
|
'agent_certified_waiting_human',
|
|
6580
|
-
'atris task current-step: selected
|
|
6836
|
+
'atris task current-step: selected row is ready to land; no agent mutation is safe',
|
|
6581
6837
|
{
|
|
6582
6838
|
status: 409,
|
|
6583
6839
|
exitCode: 1,
|
|
@@ -6989,6 +7245,7 @@ function cmdReady(args) {
|
|
|
6989
7245
|
requireMeaningfulTaskProof('atris task ready', proof);
|
|
6990
7246
|
const lesson = flag(args, '--lesson') || '';
|
|
6991
7247
|
const nextTaskInput = normalizeReviewNextTaskInput(typeof flag(args, '--next') === 'string' ? flag(args, '--next') : '');
|
|
7248
|
+
const landing = landingFlags(args);
|
|
6992
7249
|
const actor = String(flag(args, '--as') || DEFAULT_OWNER);
|
|
6993
7250
|
const resultFields = {
|
|
6994
7251
|
changed: textFlag(args, ['--changed', '--result', '--done']),
|
|
@@ -7017,6 +7274,7 @@ function cmdReady(args) {
|
|
|
7017
7274
|
lesson: typeof lesson === 'string' ? lesson : '',
|
|
7018
7275
|
nextTask: nextTaskInput.nextTask,
|
|
7019
7276
|
resultTrace: resultTrace && resultTrace.trace,
|
|
7277
|
+
landing,
|
|
7020
7278
|
});
|
|
7021
7279
|
if (!result.ready) {
|
|
7022
7280
|
console.error(`ready failed: ${result.reason}`);
|
|
@@ -7038,8 +7296,8 @@ function cmdReady(args) {
|
|
|
7038
7296
|
career_xp_status: 'pending_human_accept',
|
|
7039
7297
|
next_action: agentCertified ? certifiedReviewNextAction(nextTaskInput.nextTask) : 'agent_review_again',
|
|
7040
7298
|
rule: agentCertified
|
|
7041
|
-
? '
|
|
7042
|
-
: 'Proof is
|
|
7299
|
+
? 'Double-check complete; ready to keep moving. XP lands only after the human lands the task.'
|
|
7300
|
+
: 'Proof is ready; one more agent check before landing. XP waits for the human.',
|
|
7043
7301
|
};
|
|
7044
7302
|
if (reviewChat) {
|
|
7045
7303
|
handoff.review_chat_command = reviewChat.command;
|
|
@@ -7069,7 +7327,7 @@ function cmdReady(args) {
|
|
|
7069
7327
|
});
|
|
7070
7328
|
return;
|
|
7071
7329
|
}
|
|
7072
|
-
console.log(`ready ${taskRef(compactTaskFromProjection(projection, taskId))} v${result.event.version}
|
|
7330
|
+
console.log(`ready to land ${taskRef(compactTaskFromProjection(projection, taskId))} v${result.event.version}`);
|
|
7073
7331
|
if (resultTrace) console.log('Result trace recorded.');
|
|
7074
7332
|
console.log(handoff.rule);
|
|
7075
7333
|
for (const hint of policyHints) {
|
|
@@ -7361,6 +7619,7 @@ function cmdRevise(args) {
|
|
|
7361
7619
|
version: result.event.version,
|
|
7362
7620
|
approval_status: 'revise',
|
|
7363
7621
|
revision_count: result.event.payload.revision_count,
|
|
7622
|
+
episode: result.episode || null,
|
|
7364
7623
|
projection_path: outPath,
|
|
7365
7624
|
task: compactTaskFromProjection(projection, taskId),
|
|
7366
7625
|
});
|
|
@@ -8288,7 +8547,10 @@ function taskBoardHtml() {
|
|
|
8288
8547
|
'<div class="meta"><span class="pill">' + task.status + '</span><span class="pill">' + (task.claimed_by || 'unowned') + '</span><span class="pill">v' + task.current_version + '</span></div>',
|
|
8289
8548
|
'<div class="fact"><b>Goal</b><div id="taskGoal"></div></div>',
|
|
8290
8549
|
'<div class="fact"><b>Lineage</b><div id="taskLineage"></div></div>',
|
|
8291
|
-
'<div class="fact"><b>
|
|
8550
|
+
'<div class="fact"><b>Result</b><div id="taskHappened"></div></div>',
|
|
8551
|
+
'<div class="fact"><b>How I checked</b><div id="taskChecked"></div></div>',
|
|
8552
|
+
'<div class="fact"><b>What I tested</b><div id="taskTested"></div></div>',
|
|
8553
|
+
'<div class="fact"><b>Decision</b><div id="taskDecision"></div></div>',
|
|
8292
8554
|
'<div class="fact"><b>Proof / lesson</b><div id="taskProof"></div></div>',
|
|
8293
8555
|
'<div class="thread">' + (messages || '<div class="empty">No thread yet.</div>') + '</div>',
|
|
8294
8556
|
'<label>Add context</label><textarea id="note" placeholder="Decision, blocker, context, update..."></textarea>',
|
|
@@ -8300,9 +8562,17 @@ function taskBoardHtml() {
|
|
|
8300
8562
|
room.querySelector('h3').textContent = task.title;
|
|
8301
8563
|
$('taskGoal').textContent = task.objective || 'No matching goal yet.';
|
|
8302
8564
|
$('taskLineage').textContent = 'parent: ' + parent + ' / next: ' + children;
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
:
|
|
8565
|
+
const result = task.review && task.review.result || {};
|
|
8566
|
+
const landing = task.review && task.review.landing || {
|
|
8567
|
+
happened: result.changed,
|
|
8568
|
+
checked: result.checked,
|
|
8569
|
+
tested: task.review && task.review.proof ? 'Proof is attached below.' : '',
|
|
8570
|
+
decision: result.accept,
|
|
8571
|
+
};
|
|
8572
|
+
$('taskHappened').textContent = landing.happened || (task.review && task.review.summary) || 'No review result yet.';
|
|
8573
|
+
$('taskChecked').textContent = landing.checked || 'No check yet.';
|
|
8574
|
+
$('taskTested').textContent = landing.tested || 'No test recorded yet.';
|
|
8575
|
+
$('taskDecision').textContent = landing.decision || 'No accept action yet.';
|
|
8306
8576
|
$('taskProof').textContent = task.review && (task.review.proof || task.review.lesson)
|
|
8307
8577
|
? ((task.review.proof || 'no proof') + ' / ' + (task.review.lesson || 'no lesson'))
|
|
8308
8578
|
: 'No proof yet.';
|
|
@@ -8804,6 +9074,12 @@ async function handleTaskApi(req, res, taskDb, db) {
|
|
|
8804
9074
|
lesson: String(body.lesson || ''),
|
|
8805
9075
|
nextTask: nextTaskInput.nextTask,
|
|
8806
9076
|
resultTrace: resultTrace && resultTrace.trace,
|
|
9077
|
+
landing: body.landing || {
|
|
9078
|
+
happened: body.happened,
|
|
9079
|
+
checked: body.checked,
|
|
9080
|
+
tested: body.tested,
|
|
9081
|
+
decision: body.decision,
|
|
9082
|
+
},
|
|
8807
9083
|
});
|
|
8808
9084
|
if (!result.ready) return sendJson(res, 409, { ok: false, reason: result.reason });
|
|
8809
9085
|
const { projection, outPath } = writeDefaultProjection(taskDb, db);
|