project-tiny-context-harness 0.8.13 → 0.8.17

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.
Files changed (103) hide show
  1. package/README.md +53 -28
  2. package/assets/README.md +52 -25
  3. package/assets/README.zh-CN.md +55 -26
  4. package/assets/agents/AGENTS_CORE.md +2 -2
  5. package/assets/agents/long-task-implementation.toml +1 -1
  6. package/assets/context_templates/screen-contract.md +16 -0
  7. package/assets/skills/context_development_engineer/SKILL.md +16 -30
  8. package/assets/skills/context_development_engineer/references/engineering-design-reasoning.md +93 -0
  9. package/assets/skills/context_surface_contract/SKILL.md +13 -2
  10. package/assets/skills/context_uiux_design/SKILL.md +7 -3
  11. package/assets/skills/context_uiux_design/references/task-uiux-analysis.md +82 -0
  12. package/assets/skills/design-resource-authoring/SKILL.md +14 -8
  13. package/assets/skills/design-resource-authoring/references/downstream-handoff.md +18 -6
  14. package/assets/skills/design-resource-authoring/references/formal-selected-web-app-handoff.md +26 -8
  15. package/assets/skills/design-resource-authoring/references/implementation-feasibility.md +111 -0
  16. package/assets/skills/design-resource-authoring/references/open-design-provider.md +45 -7
  17. package/assets/skills/design-resource-authoring/references/recovery-and-writeback.md +7 -1
  18. package/assets/skills/design-resource-authoring/references/resource-selection.md +115 -3
  19. package/assets/skills/long-task-workflow/SKILL.md +9 -7
  20. package/assets/skills/long-task-workflow/agents/openai.yaml +1 -1
  21. package/assets/skills/long-task-workflow/references/authority-lifecycle.md +1 -1
  22. package/dist/commands/design-resource.js +9 -2
  23. package/dist/commands/long-task-revision.js +4 -4
  24. package/dist/index.d.ts +1 -1
  25. package/dist/lib/design-resource-handoff-bundle.js +5 -0
  26. package/dist/lib/design-resource-handoff-input-types.d.ts +1 -1
  27. package/dist/lib/design-resource-handoff-manifest-projection.js +1 -0
  28. package/dist/lib/design-resource-handoff-set-integrity.js +1 -0
  29. package/dist/lib/design-resource-handoff-shape.js +6 -2
  30. package/dist/lib/design-resource-handoff-types.d.ts +5 -0
  31. package/dist/lib/design-resource-handoff-validation.js +12 -0
  32. package/dist/lib/design-resource-implementation-feasibility-model.d.ts +35 -0
  33. package/dist/lib/design-resource-implementation-feasibility-model.js +62 -0
  34. package/dist/lib/design-resource-implementation-feasibility-shape-sections.d.ts +43 -0
  35. package/dist/lib/design-resource-implementation-feasibility-shape-sections.js +142 -0
  36. package/dist/lib/design-resource-implementation-feasibility-shape.d.ts +4 -0
  37. package/dist/lib/design-resource-implementation-feasibility-shape.js +154 -0
  38. package/dist/lib/design-resource-implementation-feasibility-source-decision-projection.d.ts +24 -0
  39. package/dist/lib/design-resource-implementation-feasibility-source-decision-projection.js +106 -0
  40. package/dist/lib/design-resource-implementation-feasibility-source-decision.d.ts +21 -0
  41. package/dist/lib/design-resource-implementation-feasibility-source-decision.js +75 -0
  42. package/dist/lib/design-resource-implementation-feasibility-types.d.ts +135 -0
  43. package/dist/lib/design-resource-implementation-feasibility-types.js +37 -0
  44. package/dist/lib/design-resource-implementation-feasibility-validation-cells.d.ts +5 -0
  45. package/dist/lib/design-resource-implementation-feasibility-validation-cells.js +125 -0
  46. package/dist/lib/design-resource-implementation-feasibility-validation-document.d.ts +4 -0
  47. package/dist/lib/design-resource-implementation-feasibility-validation-document.js +167 -0
  48. package/dist/lib/design-resource-implementation-feasibility-validation-facts.d.ts +3 -0
  49. package/dist/lib/design-resource-implementation-feasibility-validation-facts.js +76 -0
  50. package/dist/lib/design-resource-implementation-feasibility-validation-realizations.d.ts +8 -0
  51. package/dist/lib/design-resource-implementation-feasibility-validation-realizations.js +76 -0
  52. package/dist/lib/design-resource-implementation-feasibility-validation-support.d.ts +10 -0
  53. package/dist/lib/design-resource-implementation-feasibility-validation-support.js +75 -0
  54. package/dist/lib/design-resource-implementation-feasibility-validation.d.ts +3 -0
  55. package/dist/lib/design-resource-implementation-feasibility-validation.js +138 -0
  56. package/dist/lib/design-resource-symbolic-fact-shape.js +3 -1
  57. package/dist/lib/design-resource-symbolic-fact-types.d.ts +5 -0
  58. package/dist/lib/design-resource-symbolic-fact-validation.js +13 -0
  59. package/dist/lib/long-task-activation-validation.js +77 -7
  60. package/dist/lib/long-task-authority-revision-brief.js +3 -1
  61. package/dist/lib/long-task-authority-revision-summary.js +6 -2
  62. package/dist/lib/long-task-authority-revision-types.d.ts +2 -0
  63. package/dist/lib/long-task-check-runner.js +3 -296
  64. package/dist/lib/long-task-command-process.d.ts +9 -0
  65. package/dist/lib/long-task-command-process.js +175 -0
  66. package/dist/lib/long-task-delivery-validation.d.ts +5 -2
  67. package/dist/lib/long-task-delivery-validation.js +4 -4
  68. package/dist/lib/long-task-design-feasibility-binding-owners.d.ts +6 -0
  69. package/dist/lib/long-task-design-feasibility-binding-owners.js +52 -0
  70. package/dist/lib/long-task-design-feasibility-binding.d.ts +13 -0
  71. package/dist/lib/long-task-design-feasibility-binding.js +114 -0
  72. package/dist/lib/long-task-design-feasibility-source-closure.d.ts +11 -0
  73. package/dist/lib/long-task-design-feasibility-source-closure.js +78 -0
  74. package/dist/lib/long-task-design-resource-handoff.d.ts +3 -3
  75. package/dist/lib/long-task-design-resource-handoff.js +39 -3
  76. package/dist/lib/long-task-design-resource-method-binding.js +16 -4
  77. package/dist/lib/long-task-freshness.js +1 -1
  78. package/dist/lib/long-task-git.d.ts +26 -0
  79. package/dist/lib/long-task-git.js +130 -0
  80. package/dist/lib/long-task-paths.js +1 -1
  81. package/dist/lib/long-task-process-runtime-closure.js +74 -42
  82. package/dist/lib/long-task-process-table.d.ts +12 -0
  83. package/dist/lib/long-task-process-table.js +119 -0
  84. package/dist/lib/long-task-process-tree.d.ts +9 -0
  85. package/dist/lib/long-task-process-tree.js +138 -0
  86. package/dist/lib/long-task-protected-files.d.ts +1 -1
  87. package/dist/lib/long-task-protected-files.js +1 -1
  88. package/dist/lib/long-task-ui-surface-policy.d.ts +2 -1
  89. package/dist/lib/long-task-ui-surface-policy.js +7 -4
  90. package/dist/lib/long-task-ui-surface-validation.d.ts +3 -1
  91. package/dist/lib/long-task-ui-surface-validation.js +2 -2
  92. package/dist/lib/long-task-verifier-authority.js +2 -0
  93. package/dist/lib/long-task-workspace-manifest.d.ts +8 -0
  94. package/dist/lib/long-task-workspace-manifest.js +173 -0
  95. package/dist/lib/long-task-workspace-snapshot.d.ts +8 -0
  96. package/dist/lib/long-task-workspace-snapshot.js +176 -0
  97. package/dist/lib/long-task-workspace.d.ts +4 -25
  98. package/dist/lib/long-task-workspace.js +3 -432
  99. package/dist/lib/repository-path-safety.d.ts +2 -0
  100. package/dist/lib/repository-path-safety.js +36 -0
  101. package/dist/long-task-hook.js +12 -3
  102. package/dist/public-types.d.ts +1 -0
  103. package/package.json +1 -1
@@ -0,0 +1,114 @@
1
+ import { DESIGN_RESOURCE_FEASIBILITY_DECISION_SCHEMA, deriveDesignResourceFeasibilityConditionScopeSha256, parseDesignResourceFeasibilityDecisionProjections, } from "./design-resource-implementation-feasibility-source-decision.js";
2
+ import { createV1ImplementationFeasibilityTargetModel, createV2ImplementationFeasibilityTargetModel, } from "./design-resource-implementation-feasibility-model.js";
3
+ import { matchingFeasibilityBindingKeys, validateFeasibilityBindingOwnerRoots, } from "./long-task-design-feasibility-binding-owners.js";
4
+ import { validateFeasibilityBlockers, validateSelectedPlannedOwnerClaims, validateTechnicalDecisionClaim, } from "./long-task-design-feasibility-source-closure.js";
5
+ import { invalid } from "./long-task-design-resource-method-binding.js";
6
+ export function validateLongTaskDesignFeasibilityBindings(contract, contractTarget, preflight, sourceItems, options = {}) {
7
+ const document = preflight.technical_feasibility_documents.find((item) => item.target_ref === contractTarget.target.key);
8
+ if (!document) {
9
+ if (!contractTarget.binding.component_binding_refs.length)
10
+ invalid("componentless_surface_requires_blocker_only_feasibility", contractTarget.target.key);
11
+ return {
12
+ consumed_component_binding_refs: [
13
+ ...contractTarget.binding.component_binding_refs,
14
+ ],
15
+ };
16
+ }
17
+ const model = feasibilityTargetModel(preflight, contractTarget.target.key);
18
+ const decisions = compiledDecisionSources(document, sourceItems);
19
+ const outcome = contract.outcomes.find((item) => item.key === contractTarget.outcome_key);
20
+ const bindingsByKey = new Map(outcome.technical.bindings.map((binding) => [binding.key, binding]));
21
+ const componentBindings = contractTarget.binding.component_binding_refs.map((bindingRef) => {
22
+ const binding = bindingsByKey.get(bindingRef);
23
+ if (!binding)
24
+ invalid("feasibility_component_binding_unknown", `${contractTarget.target.key}:${bindingRef}`);
25
+ return binding;
26
+ });
27
+ const routeBinding = bindingsByKey.get(contractTarget.binding.route_binding_ref);
28
+ if (!routeBinding)
29
+ invalid("feasibility_route_binding_unknown", `${contractTarget.target.key}:${contractTarget.binding.route_binding_ref}`);
30
+ const hasCandidateCells = document.component_family_cells.some((cell) => cell.feasible_realizations.length > 0);
31
+ const allCellsBlockerOnly = document.component_family_cells.length > 0 &&
32
+ document.component_family_cells.every((cell) => cell.feasible_realizations.length === 0 && cell.blocker_refs.length > 0);
33
+ if (!componentBindings.length && hasCandidateCells)
34
+ invalid("feasibility_component_binding_required", contractTarget.target.key);
35
+ if (!componentBindings.length && !allCellsBlockerOnly)
36
+ invalid("componentless_surface_requires_blocker_only_feasibility", contractTarget.target.key);
37
+ validateFeasibilityBindingOwnerRoots(document, componentBindings, routeBinding);
38
+ const consumedComponentBindings = new Set();
39
+ for (const cell of document.component_family_cells) {
40
+ const blockerOnly = cell.feasible_realizations.length === 0 && cell.blocker_refs.length > 0;
41
+ if (blockerOnly)
42
+ continue;
43
+ const matching = cell.feasible_realizations
44
+ .map((realization) => ({
45
+ realization,
46
+ bindingKeys: matchingFeasibilityBindingKeys(realization, componentBindings),
47
+ }))
48
+ .filter((candidate) => candidate.bindingKeys.size > 0);
49
+ const required = cell.required_realization.realization_ref;
50
+ if (required !== null &&
51
+ (matching.length !== 1 || matching[0].realization.key !== required))
52
+ invalid("feasibility_required_realization_binding_mismatch", `${cell.key}:${required}:${matching.map((item) => item.realization.key).join(",")}`);
53
+ if (required === null && matching.length === 0)
54
+ invalid("feasibility_realization_binding_missing", cell.key);
55
+ if (required === null && matching.length > 1)
56
+ invalid("feasibility_realization_binding_ambiguous", `${cell.key}:${matching.map((item) => item.realization.key).join(",")}`);
57
+ const selected = matching.length === 1 ? matching[0] : null;
58
+ if (selected)
59
+ for (const bindingKey of selected.bindingKeys)
60
+ consumedComponentBindings.add(bindingKey);
61
+ if (required !== null)
62
+ validateTechnicalDecisionClaim(contract, contractTarget, decisions, cell.required_realization.technical_authority_source_refs, {
63
+ schema_version: DESIGN_RESOURCE_FEASIBILITY_DECISION_SCHEMA,
64
+ mode: "required_realization",
65
+ target_ref: cell.target_ref,
66
+ component_family_ref: cell.component_family_ref,
67
+ condition_scope_sha256: deriveDesignResourceFeasibilityConditionScopeSha256(document, model, cell.condition_profile_ref),
68
+ realization_ref: required,
69
+ }, `required_realization:${cell.key}`);
70
+ if (selected)
71
+ validateSelectedPlannedOwnerClaims(contract, contractTarget, document, model, decisions, selected.realization, componentBindings, cell);
72
+ }
73
+ if (!options.deferComponentBindingAttribution)
74
+ validateComponentBindingAttribution(contractTarget, consumedComponentBindings);
75
+ validateFeasibilityBlockers(contract, contractTarget, document, model, decisions);
76
+ return {
77
+ consumed_component_binding_refs: [...consumedComponentBindings].sort(),
78
+ };
79
+ }
80
+ function validateComponentBindingAttribution(contractTarget, consumedComponentBindings) {
81
+ for (const bindingRef of contractTarget.binding.component_binding_refs)
82
+ if (!consumedComponentBindings.has(bindingRef))
83
+ invalid("feasibility_component_binding_unattributed", `${contractTarget.target.key}:${bindingRef}`);
84
+ }
85
+ function feasibilityTargetModel(preflight, targetRef) {
86
+ if ("preflight_schema_version" in preflight) {
87
+ const target = preflight.handoff.targets.find((candidate) => candidate.key === targetRef);
88
+ return createV2ImplementationFeasibilityTargetModel(target, preflight.manifest);
89
+ }
90
+ const target = preflight.handoff.targets.find((candidate) => candidate.key === targetRef);
91
+ return createV1ImplementationFeasibilityTargetModel(preflight.handoff, target);
92
+ }
93
+ function compiledDecisionSources(document, sourceItems) {
94
+ const index = new Map();
95
+ for (const record of document.source_records) {
96
+ if (record.locator.kind !== "source_item")
97
+ continue;
98
+ const item = sourceItems.find((candidate) => candidate.source_path === record.path &&
99
+ candidate.key === record.locator.value);
100
+ if (!item)
101
+ invalid("feasibility_source_item_not_declared", `${record.key}:${record.path}#${record.locator.value}`);
102
+ if (item.text_sha256 !== record.locator.text_sha256)
103
+ invalid("feasibility_source_item_digest_mismatch", `${record.key}:${record.locator.text_sha256}:${item.text_sha256}`);
104
+ index.set(record.key, {
105
+ source_record_ref: record.key,
106
+ source_path: record.path,
107
+ source_item_key: item.key,
108
+ source_item_kind: item.kind,
109
+ text_sha256: item.text_sha256,
110
+ projections: parseDesignResourceFeasibilityDecisionProjections(record.path, item.key, item.normalized_text),
111
+ });
112
+ }
113
+ return index;
114
+ }
@@ -0,0 +1,11 @@
1
+ import type { DesignResourceImplementationFeasibilityTargetModel } from "./design-resource-implementation-feasibility-model.js";
2
+ import { type DesignResourceFeasibilityDecisionProjection, type DesignResourceFeasibilityDecisionSourceIndex } from "./design-resource-implementation-feasibility-source-decision.js";
3
+ import type { DesignResourceImplementationFeasibilityV1 } from "./design-resource-implementation-feasibility-types.js";
4
+ import type { DeliveryBindingV2, DeliveryContractV2 } from "./long-task-delivery-types.js";
5
+ import type { ContractDesignTarget } from "./long-task-design-resource-handoff.js";
6
+ type FeasibilityCell = DesignResourceImplementationFeasibilityV1["component_family_cells"][number];
7
+ type FeasibleRealization = FeasibilityCell["feasible_realizations"][number];
8
+ export declare function validateSelectedPlannedOwnerClaims(contract: DeliveryContractV2, contractTarget: ContractDesignTarget, document: DesignResourceImplementationFeasibilityV1, model: DesignResourceImplementationFeasibilityTargetModel, decisions: DesignResourceFeasibilityDecisionSourceIndex, realization: FeasibleRealization, bindings: DeliveryBindingV2[], cell: FeasibilityCell): void;
9
+ export declare function validateTechnicalDecisionClaim(contract: DeliveryContractV2, contractTarget: ContractDesignTarget, decisions: DesignResourceFeasibilityDecisionSourceIndex, sourceRefs: string[], expectation: DesignResourceFeasibilityDecisionProjection, label: string): void;
10
+ export declare function validateFeasibilityBlockers(contract: DeliveryContractV2, contractTarget: ContractDesignTarget, document: DesignResourceImplementationFeasibilityV1, model: DesignResourceImplementationFeasibilityTargetModel, decisions: DesignResourceFeasibilityDecisionSourceIndex): void;
11
+ export {};
@@ -0,0 +1,78 @@
1
+ import { DESIGN_RESOURCE_FEASIBILITY_DECISION_SCHEMA, deriveDesignResourceFeasibilityConditionScopeSha256, requireExactFeasibilityDecisionProjection, } from "./design-resource-implementation-feasibility-source-decision.js";
2
+ import { invalid } from "./long-task-design-resource-method-binding.js";
3
+ export function validateSelectedPlannedOwnerClaims(contract, contractTarget, document, model, decisions, realization, bindings, cell) {
4
+ for (const owner of realization.owner_candidates) {
5
+ if (owner.kind !== "planned_logical_owner")
6
+ continue;
7
+ if (!bindings.some((binding) => binding.existence === "planned" &&
8
+ (binding.key === owner.locator || binding.target === owner.locator)))
9
+ continue;
10
+ validateTechnicalDecisionClaim(contract, contractTarget, decisions, owner.authorization_source_refs, {
11
+ schema_version: DESIGN_RESOURCE_FEASIBILITY_DECISION_SCHEMA,
12
+ mode: "planned_owner_authorization",
13
+ target_ref: cell.target_ref,
14
+ component_family_ref: cell.component_family_ref,
15
+ condition_scope_sha256: deriveDesignResourceFeasibilityConditionScopeSha256(document, model, cell.condition_profile_ref),
16
+ owner_locator: owner.locator,
17
+ }, `planned_owner:${cell.key}:${owner.locator}`);
18
+ }
19
+ }
20
+ export function validateTechnicalDecisionClaim(contract, contractTarget, decisions, sourceRefs, expectation, label) {
21
+ const source = requireDecisionSource(sourceRefs, decisions, expectation, label, ["technical_obligation"], true);
22
+ const claim = exactSourceClaim(contract, source, label);
23
+ const validOutcomeClaim = claim.disposition.type === "claim" &&
24
+ claim.disposition.refs.some((ref) => ref.startsWith(`${contractTarget.outcome_key}.`));
25
+ if (!validOutcomeClaim && claim.disposition.type !== "global_constraint")
26
+ invalid("feasibility_technical_decision_claim_disposition_invalid", `${label}:${claim.key}:${claim.disposition.type}`);
27
+ }
28
+ export function validateFeasibilityBlockers(contract, contractTarget, document, model, decisions) {
29
+ for (const blocker of document.blockers) {
30
+ const source = requireDecisionSource(blocker.source_record_refs, decisions, {
31
+ schema_version: DESIGN_RESOURCE_FEASIBILITY_DECISION_SCHEMA,
32
+ mode: "feasibility_blocker",
33
+ target_ref: blocker.target_ref,
34
+ component_family_ref: blocker.component_family_ref,
35
+ condition_scope_sha256: deriveDesignResourceFeasibilityConditionScopeSha256(document, model, blocker.condition_profile_ref),
36
+ blocker_ref: blocker.key,
37
+ substrate_observation_refs: blocker.substrate_observation_refs,
38
+ }, `blocker:${blocker.key}`, ["decision", "external_confirmation"], false);
39
+ const claim = exactSourceClaim(contract, source, `blocker:${blocker.key}`);
40
+ if (source.source_item_kind === "decision") {
41
+ if (claim.disposition.type !== "decision_required")
42
+ invalid("feasibility_blocker_decision_required", `${blocker.key}:${claim.key}:${claim.disposition.type}`);
43
+ continue;
44
+ }
45
+ if (claim.disposition.type !== "external_confirmation")
46
+ invalid("feasibility_blocker_external_confirmation_required", `${blocker.key}:${claim.key}:${claim.disposition.type}`);
47
+ const impactedTargetClaims = new Set(contractTarget.target.claim_refs.map((claimRef) => `${contractTarget.outcome_key}.${claimRef}`));
48
+ for (const confirmationRef of claim.disposition.refs) {
49
+ const confirmation = contract.global.acceptance.external_confirmations.find((candidate) => candidate.key === confirmationRef);
50
+ if (!confirmation)
51
+ invalid("feasibility_blocker_confirmation_unknown", `${blocker.key}:${confirmationRef}`);
52
+ if (!confirmation.blocks_target)
53
+ invalid("feasibility_blocker_confirmation_not_blocking", `${blocker.key}:${confirmationRef}`);
54
+ if (!confirmation.impact_claims.some((claimRef) => impactedTargetClaims.has(claimRef)))
55
+ invalid("feasibility_blocker_confirmation_target_claim_missing", `${blocker.key}:${confirmationRef}`);
56
+ }
57
+ }
58
+ }
59
+ function requireDecisionSource(sourceRefs, decisions, expectation, label, allowedItemKinds, allReferencesMustBeSourceItems) {
60
+ try {
61
+ return requireExactFeasibilityDecisionProjection(sourceRefs, decisions, expectation, label, { allReferencesMustBeSourceItems, allowedItemKinds });
62
+ }
63
+ catch (error) {
64
+ invalid("feasibility_source_decision_invalid", `${label}:${message(error)}`);
65
+ }
66
+ }
67
+ function exactSourceClaim(contract, source, label) {
68
+ if (!contract.task.source_paths.includes(source.source_path))
69
+ invalid("feasibility_authority_source_not_declared", `${label}:${source.source_path}`);
70
+ const sourceRef = `${source.source_path}#${source.source_item_key}`;
71
+ const matching = contract.source_claims.filter((claim) => claim.source_ref === sourceRef);
72
+ if (matching.length !== 1)
73
+ invalid("feasibility_authority_claim_count", `${label}:${sourceRef}:${matching.length}`);
74
+ return matching[0];
75
+ }
76
+ function message(error) {
77
+ return error instanceof Error ? error.message : String(error);
78
+ }
@@ -1,6 +1,6 @@
1
1
  import type { DesignResourceHandoffPreflightV1, DesignResourceHandoffTargetV1 } from "./design-resource-handoff-types.js";
2
2
  import type { DesignResourceHandoffPreflightV2 } from "./design-resource-symbolic-fact-types.js";
3
- import type { DeliveryContractV2 } from "./long-task-delivery-types.js";
3
+ import type { CompiledSourceItemV2, DeliveryContractV2 } from "./long-task-delivery-types.js";
4
4
  export interface ContractDesignTarget {
5
5
  outcome_key: string;
6
6
  binding: DeliveryContractV2["outcomes"][number]["product"]["surface_bindings"][number];
@@ -14,5 +14,5 @@ export interface LongTaskDesignHandoffConsumer {
14
14
  consume(preflight: DesignResourceHandoffPreflightV1 | DesignResourceHandoffPreflightV2): void;
15
15
  finish(): void;
16
16
  }
17
- export declare function validateLongTaskDesignResourceHandoffs(contract: DeliveryContractV2, repository: string): Promise<void>;
18
- export declare function createLongTaskDesignHandoffConsumer(contract: DeliveryContractV2): LongTaskDesignHandoffConsumer;
17
+ export declare function validateLongTaskDesignResourceHandoffs(contract: DeliveryContractV2, repository: string, sourceItems: CompiledSourceItemV2[]): Promise<void>;
18
+ export declare function createLongTaskDesignHandoffConsumer(contract: DeliveryContractV2, sourceItems?: CompiledSourceItemV2[]): LongTaskDesignHandoffConsumer;
@@ -6,8 +6,9 @@ import { preflightParsedDesignResourceHandoffAny } from "./design-resource-hando
6
6
  import { assertSameSet, designSourceItemClaims, invalid, validateTargetIdentity, validateSymbolicTargetIdentity, validateSymbolicVerificationMethodBindings, validateVerificationMethodBindings, } from "./long-task-design-resource-method-binding.js";
7
7
  import { validateLongTaskDesignTargetCapabilities } from "./long-task-design-target-capabilities.js";
8
8
  import { assertProtectedRepositoryFile } from "./long-task-protected-files.js";
9
- export async function validateLongTaskDesignResourceHandoffs(contract, repository) {
10
- const consumer = createLongTaskDesignHandoffConsumer(contract);
9
+ import { validateLongTaskDesignFeasibilityBindings } from "./long-task-design-feasibility-binding.js";
10
+ export async function validateLongTaskDesignResourceHandoffs(contract, repository, sourceItems) {
11
+ const consumer = createLongTaskDesignHandoffConsumer(contract, sourceItems);
11
12
  for (const sourcePath of contract.task.source_paths) {
12
13
  if (!sourcePath.toLowerCase().endsWith(".md"))
13
14
  continue;
@@ -19,7 +20,7 @@ export async function validateLongTaskDesignResourceHandoffs(contract, repositor
19
20
  }
20
21
  consumer.finish();
21
22
  }
22
- export function createLongTaskDesignHandoffConsumer(contract) {
23
+ export function createLongTaskDesignHandoffConsumer(contract, sourceItems = []) {
23
24
  const contractTargets = contract.outcomes.flatMap((outcome) => outcome.product.surface_bindings.flatMap((binding) => binding.design_targets.map((target) => ({
24
25
  outcome_key: outcome.key,
25
26
  binding,
@@ -29,6 +30,7 @@ export function createLongTaskDesignHandoffConsumer(contract) {
29
30
  const indexedTargetKeys = new Set();
30
31
  const consumed = new Set();
31
32
  const validationErrors = new Map();
33
+ const feasibilityBindingRefsBySurface = new Map();
32
34
  let duplicate = null;
33
35
  const unbound = [];
34
36
  const handoffSetIntegrity = createDesignResourceHandoffSetIntegrity(invalid);
@@ -54,6 +56,14 @@ export function createLongTaskDesignHandoffConsumer(contract) {
54
56
  else
55
57
  resourcePaths.set(resource.path, identity);
56
58
  }
59
+ for (const input of preflight.handoff.technical_feasibility_inputs) {
60
+ const identity = JSON.stringify(input);
61
+ const previous = resourcePaths.get(input.path);
62
+ if (previous && previous !== identity)
63
+ recordCrossVersionIssue("handoff_set_feasibility_path_conflict", input.path);
64
+ else
65
+ resourcePaths.set(input.path, identity);
66
+ }
57
67
  if (!("preflight_schema_version" in preflight))
58
68
  handoffSetIntegrity.consume(preflight);
59
69
  for (const target of preflight.handoff.targets) {
@@ -75,6 +85,8 @@ export function createLongTaskDesignHandoffConsumer(contract) {
75
85
  target,
76
86
  };
77
87
  validateSymbolicTargetIdentity(contractTarget, indexedTarget);
88
+ const feasibility = validateLongTaskDesignFeasibilityBindings(contract, contractTarget, preflight, sourceItems, { deferComponentBindingAttribution: true });
89
+ recordFeasibilityBindingAttribution(feasibilityBindingRefsBySurface, contractTarget, feasibility.consumed_component_binding_refs);
78
90
  validateSymbolicCoverageClaims(contract, contractTarget, indexedTarget);
79
91
  validateBlockerBindings(contract, contractTarget, indexedTarget);
80
92
  }
@@ -84,6 +96,8 @@ export function createLongTaskDesignHandoffConsumer(contract) {
84
96
  target: target,
85
97
  };
86
98
  validateTargetIdentity(contractTarget, indexedTarget);
99
+ const feasibility = validateLongTaskDesignFeasibilityBindings(contract, contractTarget, preflight, sourceItems, { deferComponentBindingAttribution: true });
100
+ recordFeasibilityBindingAttribution(feasibilityBindingRefsBySurface, contractTarget, feasibility.consumed_component_binding_refs);
87
101
  validateLongTaskDesignTargetCapabilities(contract, contractTarget, indexedTarget);
88
102
  validateCoverageClaims(contract, contractTarget, indexedTarget);
89
103
  validateBlockerBindings(contract, contractTarget, indexedTarget);
@@ -106,11 +120,33 @@ export function createLongTaskDesignHandoffConsumer(contract) {
106
120
  if (validationErrors.has(contractTarget.target.key))
107
121
  throw validationErrors.get(contractTarget.target.key);
108
122
  }
123
+ validateSurfaceFeasibilityBindingAttribution(contractTargets, feasibilityBindingRefsBySurface);
109
124
  if (unbound.length)
110
125
  invalid("handoff_target_unbound", unbound[0]);
111
126
  },
112
127
  };
113
128
  }
129
+ function recordFeasibilityBindingAttribution(bySurface, contractTarget, bindingRefs) {
130
+ const key = surfaceBindingIdentity(contractTarget);
131
+ const consumed = bySurface.get(key) ?? new Set();
132
+ for (const bindingRef of bindingRefs)
133
+ consumed.add(bindingRef);
134
+ bySurface.set(key, consumed);
135
+ }
136
+ function validateSurfaceFeasibilityBindingAttribution(contractTargets, bySurface) {
137
+ const surfaces = new Map();
138
+ for (const contractTarget of contractTargets)
139
+ surfaces.set(surfaceBindingIdentity(contractTarget), contractTarget);
140
+ for (const [surfaceKey, contractTarget] of surfaces) {
141
+ const consumed = bySurface.get(surfaceKey) ?? new Set();
142
+ for (const bindingRef of contractTarget.binding.component_binding_refs)
143
+ if (!consumed.has(bindingRef))
144
+ invalid("feasibility_component_binding_unattributed", `${contractTarget.binding.key}:${bindingRef}`);
145
+ }
146
+ }
147
+ function surfaceBindingIdentity(contractTarget) {
148
+ return `${contractTarget.outcome_key}\0${contractTarget.binding.key}`;
149
+ }
114
150
  function validateSymbolicCoverageClaims(contract, contractTarget, indexed) {
115
151
  const claims = new Map(contract.source_claims.map((item) => [item.key, item]));
116
152
  const rows = indexed.preflight.handoff.coverage.filter((row) => row.target_ref === contractTarget.target.key);
@@ -10,7 +10,10 @@ export function validateTargetIdentity(contractTarget, indexed) {
10
10
  assertSameSet(target.condition_keys, handoffTarget.condition_refs, "target_conditions_mismatch", target.key);
11
11
  const resourcePaths = handoffTarget.resource_refs.map((ref) => indexed.preflight.handoff.resources.find((item) => item.key === ref)
12
12
  .path);
13
- assertSameSet(target.source_paths, [indexed.preflight.handoff_path, ...resourcePaths], "target_source_paths_mismatch", target.key);
13
+ const feasibilityPaths = indexed.preflight.handoff.technical_feasibility_inputs
14
+ .filter((item) => item.target_ref === handoffTarget.key)
15
+ .map((item) => item.path);
16
+ assertSameSet(target.source_paths, [indexed.preflight.handoff_path, ...resourcePaths, ...feasibilityPaths], "target_source_paths_mismatch", target.key);
14
17
  }
15
18
  export function validateSymbolicTargetIdentity(contractTarget, indexed) {
16
19
  const { target } = contractTarget;
@@ -25,7 +28,10 @@ export function validateSymbolicTargetIdentity(contractTarget, indexed) {
25
28
  invalid("v2_ground_method_bindings_forbidden", target.key);
26
29
  const resourcePaths = handoffTarget.resource_refs.map((ref) => indexed.preflight.handoff.resources.find((item) => item.key === ref)
27
30
  .path);
28
- assertSameSet(target.source_paths, [indexed.preflight.handoff_path, ...resourcePaths], "target_source_paths_mismatch", target.key);
31
+ const feasibilityPaths = indexed.preflight.handoff.technical_feasibility_inputs
32
+ .filter((item) => item.target_ref === handoffTarget.key)
33
+ .map((item) => item.path);
34
+ assertSameSet(target.source_paths, [indexed.preflight.handoff_path, ...resourcePaths, ...feasibilityPaths], "target_source_paths_mismatch", target.key);
29
35
  }
30
36
  export function validateSymbolicVerificationMethodBindings(contract, contractTarget, indexed, claimsBySourceItem) {
31
37
  const target = contractTarget.target;
@@ -49,6 +55,7 @@ export function validateSymbolicVerificationMethodBindings(contract, contractTar
49
55
  const assertion = check.positive_assertions.find((item) => item.key === binding.assertion_ref);
50
56
  if (!assertion)
51
57
  invalid("v2_verification_method_assertion_unknown", `${target.key}:${binding.method}:${binding.assertion_ref}`);
58
+ const assertedClaims = claimsAssertedByRootOrMethod(target, check, assertion.claims);
52
59
  for (const capability of requiredCapabilities(binding.method))
53
60
  if (!assertion.evidence_capabilities.includes(capability))
54
61
  invalid("v2_verification_method_capability_required", `${target.key}:${binding.method}:${capability}`);
@@ -60,7 +67,7 @@ export function validateSymbolicVerificationMethodBindings(contract, contractTar
60
67
  const rule = preflight.manifest.fact_rules.find((item) => item.key === expectation.fact_rule_ref);
61
68
  for (const sourceItemRef of rule.source_item_refs)
62
69
  for (const claimRef of claimsBySourceItem.get(sourceItemRef) ?? [])
63
- if (!assertion.claims.includes(claimRef))
70
+ if (!assertedClaims.has(claimRef))
64
71
  invalid("v2_verification_method_claim_not_asserted", `${target.key}:${binding.method}:${sourceItemRef}:${claimRef}`);
65
72
  boundObligationRefs.push(expectation.obligation_ref);
66
73
  }
@@ -145,12 +152,13 @@ export function validateVerificationMethodBindings(target, check, facts, proofs,
145
152
  const assertion = check.positive_assertions.find((item) => item.key === binding.assertion_ref);
146
153
  if (!assertion)
147
154
  invalid("verification_method_assertion_unknown", `${target.key}:${binding.method}:${binding.assertion_ref}`);
155
+ const assertedClaims = claimsAssertedByRootOrMethod(target, check, assertion.claims);
148
156
  const sourceItems = new Set(facts
149
157
  .filter((fact) => proofs.some((proof) => proof.fact_ref === fact.key && proof.method === binding.method))
150
158
  .flatMap((fact) => fact.source_item_refs));
151
159
  for (const sourceItemRef of sourceItems)
152
160
  for (const claimRef of claimsBySourceItem.get(sourceItemRef) ?? [])
153
- if (!assertion.claims.includes(claimRef))
161
+ if (!assertedClaims.has(claimRef))
154
162
  invalid("verification_method_claim_not_asserted", `${target.key}:${binding.method}:${sourceItemRef}:${claimRef}`);
155
163
  for (const capability of requiredCapabilities(binding.method))
156
164
  if (!assertion.evidence_capabilities.includes(capability))
@@ -173,6 +181,10 @@ export function validateVerificationMethodBindings(target, check, facts, proofs,
173
181
  }
174
182
  assertSameSet(boundFactRefs, facts.map((fact) => fact.key), "design_method_fact_refs_mismatch", target.key);
175
183
  }
184
+ function claimsAssertedByRootOrMethod(target, check, methodClaims) {
185
+ const rootAssertion = check.positive_assertions.find((item) => item.key === target.conformance_assertion_ref);
186
+ return new Set([...(rootAssertion?.claims ?? []), ...methodClaims]);
187
+ }
176
188
  function designFactExpectation(indexed, factRef, proofRef) {
177
189
  const handoff = indexed.preflight.handoff;
178
190
  const fact = handoff.facts.find((item) => item.key === factRef);
@@ -8,7 +8,7 @@ import { parseDeliveryContractBundle } from "./long-task-delivery-parser.js";
8
8
  export async function deliveryCompileFreshness(compiled) {
9
9
  const findings = [];
10
10
  try {
11
- const currentContract = await parseDeliveryContractBundle(compiled.workdir);
11
+ const currentContract = await parseDeliveryContractBundle(compiled.workdir, compiled.repository_root, { validate_structure: false });
12
12
  if (sha256Hex(canonicalValueJson(currentContract.contract)) !==
13
13
  compiled.contract_sha256)
14
14
  findings.push(`contract_changed_after_compile:${compiled.contract_file}`);
@@ -0,0 +1,26 @@
1
+ export declare class GitCommandError extends Error {
2
+ readonly exitCode: number | null;
3
+ readonly signal: NodeJS.Signals | null;
4
+ readonly stdoutBytes: number;
5
+ readonly stderrBytes: number;
6
+ constructor(exitCode: number | null, signal: NodeJS.Signals | null, argv: string[], stdout: Buffer, stderr: Buffer);
7
+ }
8
+ export declare function repositoryRoot(start: string): Promise<string>;
9
+ export declare function gitCommonDir(root: string): Promise<string>;
10
+ export declare function currentGitState(root: string): Promise<{
11
+ head: string;
12
+ tree: string;
13
+ dirty: string[];
14
+ }>;
15
+ export declare function currentGitTree(root: string): Promise<string>;
16
+ export declare function gitPath(root: string, pathSpec: string): Promise<string>;
17
+ export declare function gitConfigGet(root: string, name: string): Promise<string | null>;
18
+ export declare function gitEffectiveConfigGet(root: string, name: string): Promise<string | null>;
19
+ export declare function gitConfigSet(root: string, name: string, value: string): Promise<void>;
20
+ export declare function gitConfigUnset(root: string, name: string): Promise<void>;
21
+ export declare function repoRelative(rootInput: string, fileInput: string): string;
22
+ export declare function gitOutput(root: string, argv: string[]): Promise<string>;
23
+ export declare function gitVoid(root: string, argv: string[]): Promise<void>;
24
+ export declare function gitBuffer(root: string, argv: string[]): Promise<Buffer>;
25
+ export declare function gitBufferInput(root: string, argv: string[], input?: Buffer): Promise<Buffer>;
26
+ export declare function splitGitZero(value: Buffer): string[];
@@ -0,0 +1,130 @@
1
+ import { spawn } from "node:child_process";
2
+ import { stat } from "node:fs/promises";
3
+ import path from "node:path";
4
+ export class GitCommandError extends Error {
5
+ exitCode;
6
+ signal;
7
+ stdoutBytes;
8
+ stderrBytes;
9
+ constructor(exitCode, signal, argv, stdout, stderr) {
10
+ const stderrText = stderr.toString("utf8").trim();
11
+ super(`git_exit:${exitCode ?? "null"}:${argv.join(" ")}:signal=${signal ?? "none"}:stdout_bytes=${stdout.length}:stderr=${stderrText}`);
12
+ this.name = "GitCommandError";
13
+ this.exitCode = exitCode;
14
+ this.signal = signal;
15
+ this.stdoutBytes = stdout.length;
16
+ this.stderrBytes = stderr.length;
17
+ }
18
+ }
19
+ export async function repositoryRoot(start) {
20
+ const resolved = path.resolve(start);
21
+ const gitEntry = await stat(path.join(resolved, ".git")).catch(() => null);
22
+ if (gitEntry?.isDirectory() || gitEntry?.isFile())
23
+ return resolved;
24
+ return path.resolve(await gitOutput(resolved, ["rev-parse", "--show-toplevel"]));
25
+ }
26
+ export async function gitCommonDir(root) {
27
+ return path.resolve(await gitOutput(root, [
28
+ "rev-parse",
29
+ "--path-format=absolute",
30
+ "--git-common-dir",
31
+ ]));
32
+ }
33
+ export async function currentGitState(root) {
34
+ const [head, tree, raw] = await Promise.all([
35
+ gitOutput(root, ["rev-parse", "HEAD"]),
36
+ gitOutput(root, ["rev-parse", "HEAD^{tree}"]),
37
+ gitOutput(root, ["status", "--short", "--untracked-files=all"]),
38
+ ]);
39
+ return {
40
+ head,
41
+ tree,
42
+ dirty: raw ? raw.split(/\r?\n/u).filter(Boolean) : [],
43
+ };
44
+ }
45
+ export async function currentGitTree(root) {
46
+ return gitOutput(root, ["rev-parse", "HEAD^{tree}"]);
47
+ }
48
+ export async function gitPath(root, pathSpec) {
49
+ return path.resolve(await gitOutput(root, [
50
+ "rev-parse",
51
+ "--path-format=absolute",
52
+ "--git-path",
53
+ pathSpec,
54
+ ]));
55
+ }
56
+ export async function gitConfigGet(root, name) {
57
+ try {
58
+ return await gitOutput(root, ["config", "--local", "--get", name]);
59
+ }
60
+ catch (error) {
61
+ if (error instanceof GitCommandError && error.exitCode === 1)
62
+ return null;
63
+ throw error;
64
+ }
65
+ }
66
+ export async function gitEffectiveConfigGet(root, name) {
67
+ try {
68
+ return await gitOutput(root, ["config", "--get", name]);
69
+ }
70
+ catch (error) {
71
+ if (error instanceof GitCommandError && error.exitCode === 1)
72
+ return null;
73
+ throw error;
74
+ }
75
+ }
76
+ export async function gitConfigSet(root, name, value) {
77
+ await gitVoid(root, ["config", "--local", name, value]);
78
+ }
79
+ export async function gitConfigUnset(root, name) {
80
+ try {
81
+ await gitVoid(root, ["config", "--local", "--unset-all", name]);
82
+ }
83
+ catch (error) {
84
+ if (!(error instanceof GitCommandError) || error.exitCode !== 5)
85
+ throw error;
86
+ }
87
+ }
88
+ export function repoRelative(rootInput, fileInput) {
89
+ const value = path
90
+ .relative(path.resolve(rootInput), path.resolve(fileInput))
91
+ .replace(/\\/gu, "/");
92
+ if (value.startsWith("../") || path.isAbsolute(value))
93
+ throw new Error(`path_outside_repository:${fileInput}`);
94
+ return value;
95
+ }
96
+ export async function gitOutput(root, argv) {
97
+ return (await gitBuffer(root, argv)).toString("utf8").trim();
98
+ }
99
+ export async function gitVoid(root, argv) {
100
+ await gitBuffer(root, argv);
101
+ }
102
+ export async function gitBuffer(root, argv) {
103
+ return gitBufferInput(root, argv);
104
+ }
105
+ export async function gitBufferInput(root, argv, input) {
106
+ return new Promise((resolve, reject) => {
107
+ const child = spawn("git", argv, {
108
+ cwd: root,
109
+ shell: false,
110
+ windowsHide: true,
111
+ });
112
+ const stdout = [];
113
+ const stderr = [];
114
+ child.stdout.on("data", (chunk) => stdout.push(chunk));
115
+ child.stderr.on("data", (chunk) => stderr.push(chunk));
116
+ child.on("error", reject);
117
+ child.stdin.end(input);
118
+ child.on("close", (code, signal) => {
119
+ const stdoutBytes = Buffer.concat(stdout);
120
+ const stderrBytes = Buffer.concat(stderr);
121
+ if (code === 0)
122
+ resolve(stdoutBytes);
123
+ else
124
+ reject(new GitCommandError(code, signal, argv, stdoutBytes, stderrBytes));
125
+ });
126
+ });
127
+ }
128
+ export function splitGitZero(value) {
129
+ return value.toString("utf8").split("\0").filter(Boolean);
130
+ }
@@ -2,7 +2,7 @@ import path from "node:path";
2
2
  import { resolveInsideRepository } from "./long-task-workspace.js";
3
3
  export function parseRepositoryPattern(value, label = "repository_pattern") {
4
4
  const normalized = canonicalRepositoryPath(value, label, "pattern");
5
- if (/[\[\]{}()]/u.test(normalized))
5
+ if (/[\[\]{}]/u.test(normalized))
6
6
  throw new Error(`unsupported_repository_pattern_syntax:${label}:${value}`);
7
7
  const segments = normalized.split("/").map((segment) => {
8
8
  if (segment === "**")